<commit_before>/*
    ChibiOS - Copyright (C) 2006..2015 Giovanni Di Sirio

    Licensed under the Apache License, Version 2.0 (the "License");
    you may not use this file except in compliance with the License.
    You may obtain a copy of the License at

        http://www.apache.org/licenses/LICENSE-2.0

    Unless required by applicable law or agreed to in writing, software
    distributed under the License is distributed on an "AS IS" BASIS,
    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    See the License for the specific language governing permissions and
    limitations under the License.
*/

#include "ch.h"
#include "hal.h"

#include "analog.h"
#include "encoder.h"
#include "encoderfoaw.h"
#include "simulation.pb.h"
#include "messageutil.h"
#include "filter/movingaverage.h"

#include "blink.h"
#include "saconfig.h"
#include "utility.h"
#include "sautility.h"

#include "parameters.h"

#include <array>
#include <type_traits>

#include "haptic.h"
#include "simbicycle.h"
#include "transmitter.h"

#if defined(USE_BICYCLE_KINEMATIC_MODEL)
#include "bicycle/kinematic.h" // simplified bicycle model
#else // No Whipple model simplifications
#include "bicycle/whipple.h"
#include "kalman.h" // kalman filter observer
#endif

namespace {
#if defined(USE_BICYCLE_KINEMATIC_MODEL)
    using model_t = model::BicycleKinematic;
    using observer_t = std::nullptr_t;
    using haptic_drive_t = haptic::Handlebar0;
#else
    using model_t = model::BicycleWhipple;
    using observer_t = observer::Kalman<model_t>;
#endif
    using bicycle_t = sim::Bicycle<model_t, observer_t>;

    // sensors
    Analog<10> analog; // per channel buffer depth of 10

    Encoder encoder_steer(sa::RLS_ROLIN_ENC, sa::RLS_ROLIN_ENC_INDEX_CFG);
    EncoderFoaw<float, 32> encoder_rear_wheel(sa::RLS_GTS35_ENC,
                                              sa::RLS_GTS35_ENC_CFG,
                                              MS2ST(1),
                                              3.0f);
#if defined(USE_BICYCLE_KINEMATIC_MODEL)
    filter::MovingAverage<float, 5> velocity_filter;
#else
    constexpr float fixed_v = 5.0f; // fixed bicycle velocity
#endif

    constexpr float mass_upper = sa::FULL_ASSEMBLY_INERTIA_WITHOUT_WEIGHT;
    constexpr float mass_lower = sa::UPPER_ASSEMBLY_INERTIA_PHYSICAL;

    // pose calculation loop
    constexpr systime_t pose_loop_period = US2ST(8333); // update pose at 120 Hz

    // dynamics loop
    constexpr systime_t dynamics_loop_period = MS2ST(1); // 1 ms -> 1 kHz

    // Suspends the invoking thread until the system time arrives to the
    // specified value.
    // The system time is assumed to be between prev and time else the call is
    // assumed to have been called outside the allowed time interval, in this
    // case the thread yields the time slot and no sleep is performed.
    systime_t chThdSleepUntilWindowedOrYield(systime_t prev, systime_t next) {
        systime_t time;

        chSysLock();
        time = chVTGetSystemTimeX();
        if (chVTIsTimeWithinX(time, prev, next)) {
            chThdSleepS(next - time);
        } else {
            chSchDoYieldS();
        }
        chSysUnlock();

        return next;
    }

    template <typename T>
    struct observer_initializer{
        template <typename S = T>
        typename std::enable_if<std::is_same<typename S::observer_t, observer::Kalman<model_t>>::value, void>::type
            initialize(S& bicycle) {
            typename S::observer_t& observer = bicycle.observer();
            observer.set_Q(10*parameters::defaultvalue::kalman::Q(observer.dt()));
            // Reduce steer measurement noise covariance
            observer.set_R(parameters::defaultvalue::kalman::R);

            // prime the Kalman gain matrix
            bicycle.prime_observer();

            // We start with steer angle equal to the measurement and all other state elements at zero.
            model_t::state_t x0 = model_t::state_t::Zero();
            model_t::set_state_element(x0, model_t::state_index_t::steer_angle,
                    util::encoder_count<float>(encoder_steer));
            observer.set_x(x0);
        }
        template <typename S = T>
        typename std::enable_if<!std::is_same<typename S::observer_t, observer::Kalman<model_t>>::value, void>::type
            initialize(S& bicycle) {
            // no-op
            (void)bicycle;
        }

        template <typename S = T>
        typename std::enable_if<std::is_same<typename S::observer_t, observer::Kalman<model_t>>::value, void>::type
            set_message(S& bicycle, SimulationMessage* msg) {
            message::set_kalman_gain(&msg->kalman, bicycle.observer());
            msg->has_kalman = true;
        }
        template <typename S = T>
        typename std::enable_if<!std::is_same<typename S::observer_t, observer::Kalman<model_t>>::value, void>::type
            set_message(S& bicycle, SimulationMessage* msg) {
            // no-op
            (void)bicycle;
            (void)msg;
        }
    };

    struct pose_thread_arg {
        bicycle_t& bicycle;
        message::Transmitter& transmitter;
    };
    THD_WORKING_AREA(wa_pose_thread, 2048);
    THD_FUNCTION(pose_thread, arg) {
        pose_thread_arg* a = static_cast<pose_thread_arg*>(arg);

        chRegSetThreadName("pose");
        systime_t deadline = chVTGetSystemTime();
        while (true) {
            a->bicycle.update_kinematics();
            BicyclePoseMessage* msg = a->transmitter.alloc_pose_message();
            if (msg != nullptr) {
                *msg = a->bicycle.pose();
                if (a->transmitter.transmit_async(msg) != MSG_OK) {
                    // Discard pose message if transmission fails. As the
                    // receiver requires the most recent pose, we should not
                    // wait to queue a pose message.
                    a->transmitter.free_message(msg);
                }
            }

            deadline = chThdSleepUntilWindowedOrYield(deadline, deadline + pose_loop_period);
        }
    }
} // namespace

int main(void) {
    // System initializations.
    // - HAL initialization, this also initializes the configured device drivers
    //   and performs the board-specific initializations.
    // - Kernel initialization, the main() function becomes a thread and the
    //   RTOS is active.
    halInit();
    chSysInit();

    // Create LED blink thread
    chBlinkThreadCreateStatic();

    // Start sensors.
    // Encoder:
    //   Initialize encoder driver 5 on pins PA0, PA1 (EXT2-4, EXT2-8).
    //   Pins for encoder driver 3 are already set in board.h.
    palSetLineMode(LINE_TIM5_CH1, PAL_MODE_ALTERNATE(2) | PAL_STM32_PUPDR_FLOATING);
    palSetLineMode(LINE_TIM5_CH2, PAL_MODE_ALTERNATE(2) | PAL_STM32_PUPDR_FLOATING);
    encoder_steer.start();
    encoder_rear_wheel.start();
    analog.start(10000); // trigger ADC conversion at 10 kHz

    //Set torque measurement enable line low.
    //The output of the Kistler torque sensor is not valid until after a falling edge
    //on the measurement line and it is held low. The 'LINE_TORQUE_MEAS_EN' line is
    //reversed due to NPN switch Q1.
    palClearLine(LINE_TORQUE_MEAS_EN);
    chThdSleepMilliseconds(1);
    palSetLine(LINE_TORQUE_MEAS_EN);

    // Start DAC1 driver and set output pin as analog as suggested in Reference Manual.
    // The default line configuration is OUTPUT_OPENDRAIN_PULLUP for SPI1_ENC1_NSS
    // and must be changed to use as analog output.
    palSetLineMode(LINE_KOLLM_ACTL_TORQUE, PAL_MODE_INPUT_ANALOG);
    dacStart(sa::KOLLM_DAC, sa::KOLLM_DAC_CFG);
#if defined(USE_BICYCLE_KINEMATIC_MODEL)
    sa::set_kollmorgen_torque(0.0f);
#else // defined(USE_BICYCLE_KINEMATIC_MODEL)
    sa::set_kollmorgen_velocity(0.0f);
#endif // defined(USE_BICYCLE_KINEMATIC_MODEL)

    // Initialize bicycle. The initial velocity is important as we use it to prime
    // the Kalman gain matrix.
    bicycle_t bicycle(
#if defined(USE_BICYCLE_KINEMATIC_MODEL)
            0.0f,
#else
            fixed_v,
#endif
            static_cast<model::real_t>(dynamics_loop_period)/CH_CFG_ST_FREQUENCY);

#if defined(USE_BICYCLE_KINEMATIC_MODEL)
    // Initialize handlebar object to calculate motor drive feedback torque
    haptic_drive_t haptic_drive(bicycle.model());
#endif

    // Initialize handlebar object to estimate torque due to handlebar inertia.
    haptic::Handlebar2 handlebar_inertia(bicycle.model(), sa::UPPER_ASSEMBLY_INERTIA_PHYSICAL);

    observer_initializer<observer_t> oi;
    oi.initialize(bicycle);

    // Initialize time measurements
    time_measurement_t computation_time_measurement;
    time_measurement_t transmission_time_measurement;
    chTMObjectInit(&computation_time_measurement);
    chTMObjectInit(&transmission_time_measurement);

    // Initialize USB data transmission
    message::Transmitter transmitter;
    {   // Transmit initial message containing gitsha1, model, and observer data.
        SimulationMessage* msg = transmitter.alloc_simulation_message();
        *msg = SimulationMessage_init_zero;
        msg->timestamp = chVTGetSystemTime();
        message::set_simulation_full_model_observer(msg, bicycle);
        transmitter.transmit(msg); // This blocks until USB data starts getting read
    }
    transmitter.start(NORMALPRIO + 1); // start transmission thread

    // Start running pose calculation thread
    pose_thread_arg a{bicycle, transmitter};
    chThdCreateStatic(wa_pose_thread, sizeof(wa_pose_thread),
            NORMALPRIO - 1, pose_thread, static_cast<void*>(&a));

    // Normal main() thread activity. This is the dynamics simulation loop.
    systime_t deadline = chVTGetSystemTime();
    while (true) {
        systime_t starttime = chVTGetSystemTime();
        chTMStartMeasurementX(&computation_time_measurement);
        const float roll_torque = 0.0f;

        // get sensor measurements
        const float kistler_torque = sa::get_kistler_sensor_torque(analog.get_adc12());
        const float motor_torque = sa::get_kollmorgen_motor_torque(analog.get_adc13());
        const float steer_angle = util::encoder_count<float>(encoder_steer);
        const float rear_wheel_angle = std::fmod(-util::encoder_count<float>(encoder_rear_wheel),
                                                 constants::two_pi);
#if defined(USE_BICYCLE_KINEMATIC_MODEL)
        const float v = velocity_filter.output(
                -sa::REAR_WHEEL_RADIUS*(util::encoder_rate(encoder_rear_wheel)));
#else
        constexpr float v = fixed_v;
#endif

        // yaw angle, just use previous state value
        const float yaw_angle = util::wrap(bicycle.pose().yaw);

        // calculate rider applied torque
        const float steer_torque = kistler_torque + mass_upper/mass_lower*(kistler_torque - motor_torque);

        // simulate bicycle
        bicycle.set_v(v);

        bicycle.update_dynamics(roll_torque, steer_torque, yaw_angle, steer_angle, rear_wheel_angle);

        // generate handlebar torque or velocity reference
#if defined(USE_BICYCLE_KINEMATIC_MODEL)
        const float desired_torque = haptic_drive.torque(model_t::get_state_part(bicycle.full_state()));
        const dacsample_t handlebar_reference_dac = sa::set_kollmorgen_torque(desired_torque);
#else // defined(USE_BICYCLE_KINEMATIC_MODEL)
        const float desired_velocity =
            model_t::get_full_state_element(bicycle.full_state(),
                                            model_t::full_state_index_t::steer_rate);
        const dacsample_t handlebar_reference_dac = sa::set_kollmorgen_velocity(desired_velocity);
#endif // defined(USE_BICYCLE_KINEMATIC_MODEL)
        chTMStopMeasurementX(&computation_time_measurement);

        {   // prepare message for transmission
            SimulationMessage* msg = transmitter.alloc_simulation_message();
            if (msg != nullptr) {
                *msg = SimulationMessage_init_zero;
                msg->timestamp = starttime;
                msg->model.v = bicycle.v();
                msg->model.has_v = true;
                msg->has_model = true;
                message::set_bicycle_input(
                        &msg->input,
                        (model_t::input_t() << roll_torque, steer_torque).finished());
                msg->has_input = true;
                message::set_simulation_state(msg, bicycle);
                message::set_simulation_auxiliary_state(msg, bicycle);
                oi.set_message(bicycle, msg);
                message::set_simulation_actuators(msg, handlebar_reference_dac);
                message::set_simulation_sensors(
                        msg,
                        analog.get_adc12(),
                        analog.get_adc13(),
                        encoder_steer.count(),
                        encoder_rear_wheel.count());
                message::set_simulation_timing(
                        msg,
                        computation_time_measurement.last,
                        transmission_time_measurement.last);
                if (transmitter.transmit_async(msg) != MSG_OK) {
                    // Discard simulation message if it cannot be processed quickly enough.
                    transmitter.free_message(msg);
                }
            }
        }
        deadline = chThdSleepUntilWindowedOrYield(deadline, deadline + dynamics_loop_period);
    }
}
<commit_msg>Remove use of Kalman filter for state estimate<commit_after>/*
    ChibiOS - Copyright (C) 2006..2015 Giovanni Di Sirio

    Licensed under the Apache License, Version 2.0 (the "License");
    you may not use this file except in compliance with the License.
    You may obtain a copy of the License at

        http://www.apache.org/licenses/LICENSE-2.0

    Unless required by applicable law or agreed to in writing, software
    distributed under the License is distributed on an "AS IS" BASIS,
    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    See the License for the specific language governing permissions and
    limitations under the License.
*/

#include "ch.h"
#include "hal.h"

#include "analog.h"
#include "encoder.h"
#include "encoderfoaw.h"
#include "simulation.pb.h"
#include "messageutil.h"
#include "filter/movingaverage.h"

#include "blink.h"
#include "saconfig.h"
#include "utility.h"
#include "sautility.h"

#include "parameters.h"

#include <array>
#include <type_traits>

#include "haptic.h"
#include "simbicycle.h"
#include "transmitter.h"

#if defined(USE_BICYCLE_KINEMATIC_MODEL)
#include "bicycle/kinematic.h" // simplified bicycle model
#else // No Whipple model simplifications
#include "bicycle/whipple.h"
#endif

namespace {
#if defined(USE_BICYCLE_KINEMATIC_MODEL)
    using model_t = model::BicycleKinematic;
    using haptic_drive_t = haptic::Handlebar0;
#else
    using model_t = model::BicycleWhipple;
#endif
    using observer_t = std::nullptr_t;
    using bicycle_t = sim::Bicycle<model_t, observer_t>;

    // sensors
    Analog<10> analog; // per channel buffer depth of 10

    Encoder encoder_steer(sa::RLS_ROLIN_ENC, sa::RLS_ROLIN_ENC_INDEX_CFG);
    EncoderFoaw<float, 32> encoder_rear_wheel(sa::RLS_GTS35_ENC,
                                              sa::RLS_GTS35_ENC_CFG,
                                              MS2ST(1),
                                              3.0f);
#if defined(USE_BICYCLE_KINEMATIC_MODEL)
    filter::MovingAverage<float, 5> velocity_filter;
#else
    constexpr float fixed_v = 5.0f; // fixed bicycle velocity
#endif

    constexpr float mass_upper = sa::FULL_ASSEMBLY_INERTIA_WITHOUT_WEIGHT;
    constexpr float mass_lower = sa::UPPER_ASSEMBLY_INERTIA_PHYSICAL;

    // pose calculation loop
    constexpr systime_t pose_loop_period = US2ST(8333); // update pose at 120 Hz

    // dynamics loop
    constexpr systime_t dynamics_loop_period = MS2ST(1); // 1 ms -> 1 kHz

    // Suspends the invoking thread until the system time arrives to the
    // specified value.
    // The system time is assumed to be between prev and time else the call is
    // assumed to have been called outside the allowed time interval, in this
    // case the thread yields the time slot and no sleep is performed.
    systime_t chThdSleepUntilWindowedOrYield(systime_t prev, systime_t next) {
        systime_t time;

        chSysLock();
        time = chVTGetSystemTimeX();
        if (chVTIsTimeWithinX(time, prev, next)) {
            chThdSleepS(next - time);
        } else {
            chSchDoYieldS();
        }
        chSysUnlock();

        return next;
    }

    struct pose_thread_arg {
        bicycle_t& bicycle;
        message::Transmitter& transmitter;
    };
    THD_WORKING_AREA(wa_pose_thread, 2048);
    THD_FUNCTION(pose_thread, arg) {
        pose_thread_arg* a = static_cast<pose_thread_arg*>(arg);

        chRegSetThreadName("pose");
        systime_t deadline = chVTGetSystemTime();
        while (true) {
            a->bicycle.update_kinematics();
            BicyclePoseMessage* msg = a->transmitter.alloc_pose_message();
            if (msg != nullptr) {
                *msg = a->bicycle.pose();
                if (a->transmitter.transmit_async(msg) != MSG_OK) {
                    // Discard pose message if transmission fails. As the
                    // receiver requires the most recent pose, we should not
                    // wait to queue a pose message.
                    a->transmitter.free_message(msg);
                }
            }

            deadline = chThdSleepUntilWindowedOrYield(deadline, deadline + pose_loop_period);
        }
    }
} // namespace

int main(void) {
    // System initializations.
    // - HAL initialization, this also initializes the configured device drivers
    //   and performs the board-specific initializations.
    // - Kernel initialization, the main() function becomes a thread and the
    //   RTOS is active.
    halInit();
    chSysInit();

    // Create LED blink thread
    chBlinkThreadCreateStatic();

    // Start sensors.
    // Encoder:
    //   Initialize encoder driver 5 on pins PA0, PA1 (EXT2-4, EXT2-8).
    //   Pins for encoder driver 3 are already set in board.h.
    palSetLineMode(LINE_TIM5_CH1, PAL_MODE_ALTERNATE(2) | PAL_STM32_PUPDR_FLOATING);
    palSetLineMode(LINE_TIM5_CH2, PAL_MODE_ALTERNATE(2) | PAL_STM32_PUPDR_FLOATING);
    encoder_steer.start();
    encoder_rear_wheel.start();
    analog.start(10000); // trigger ADC conversion at 10 kHz

    //Set torque measurement enable line low.
    //The output of the Kistler torque sensor is not valid until after a falling edge
    //on the measurement line and it is held low. The 'LINE_TORQUE_MEAS_EN' line is
    //reversed due to NPN switch Q1.
    palClearLine(LINE_TORQUE_MEAS_EN);
    chThdSleepMilliseconds(1);
    palSetLine(LINE_TORQUE_MEAS_EN);

    // Start DAC1 driver and set output pin as analog as suggested in Reference Manual.
    // The default line configuration is OUTPUT_OPENDRAIN_PULLUP for SPI1_ENC1_NSS
    // and must be changed to use as analog output.
    palSetLineMode(LINE_KOLLM_ACTL_TORQUE, PAL_MODE_INPUT_ANALOG);
    dacStart(sa::KOLLM_DAC, sa::KOLLM_DAC_CFG);
#if defined(USE_BICYCLE_KINEMATIC_MODEL)
    sa::set_kollmorgen_torque(0.0f);
#else // defined(USE_BICYCLE_KINEMATIC_MODEL)
    sa::set_kollmorgen_velocity(0.0f);
#endif // defined(USE_BICYCLE_KINEMATIC_MODEL)

    // Initialize bicycle.
    bicycle_t bicycle(
#if defined(USE_BICYCLE_KINEMATIC_MODEL)
            0.0f,
#else
            fixed_v,
#endif
            static_cast<model::real_t>(dynamics_loop_period)/CH_CFG_ST_FREQUENCY);

#if defined(USE_BICYCLE_KINEMATIC_MODEL)
    // Initialize handlebar object to calculate motor drive feedback torque
    haptic_drive_t haptic_drive(bicycle.model());
#endif

    // Initialize handlebar object to estimate torque due to handlebar inertia.
    haptic::Handlebar2 handlebar_inertia(bicycle.model(), sa::UPPER_ASSEMBLY_INERTIA_PHYSICAL);

    // Initialize time measurements
    time_measurement_t computation_time_measurement;
    time_measurement_t transmission_time_measurement;
    chTMObjectInit(&computation_time_measurement);
    chTMObjectInit(&transmission_time_measurement);

    // Initialize USB data transmission
    message::Transmitter transmitter;
    {   // Transmit initial message containing gitsha1, model, and observer data.
        SimulationMessage* msg = transmitter.alloc_simulation_message();
        *msg = SimulationMessage_init_zero;
        msg->timestamp = chVTGetSystemTime();
        message::set_simulation_full_model_observer(msg, bicycle);
        transmitter.transmit(msg); // This blocks until USB data starts getting read
    }
    transmitter.start(NORMALPRIO + 1); // start transmission thread

    // Start running pose calculation thread
    pose_thread_arg a{bicycle, transmitter};
    chThdCreateStatic(wa_pose_thread, sizeof(wa_pose_thread),
            NORMALPRIO - 1, pose_thread, static_cast<void*>(&a));

    // Normal main() thread activity. This is the dynamics simulation loop.
    systime_t deadline = chVTGetSystemTime();
    while (true) {
        systime_t starttime = chVTGetSystemTime();
        chTMStartMeasurementX(&computation_time_measurement);
        const float roll_torque = 0.0f;

        // get sensor measurements
        const float kistler_torque = sa::get_kistler_sensor_torque(analog.get_adc12());
        const float motor_torque = sa::get_kollmorgen_motor_torque(analog.get_adc13());
        const float steer_angle = util::encoder_count<float>(encoder_steer);
        const float rear_wheel_angle = std::fmod(-util::encoder_count<float>(encoder_rear_wheel),
                                                 constants::two_pi);
#if defined(USE_BICYCLE_KINEMATIC_MODEL)
        const float v = velocity_filter.output(
                -sa::REAR_WHEEL_RADIUS*(util::encoder_rate(encoder_rear_wheel)));
#else
        constexpr float v = fixed_v;
#endif

        // yaw angle, just use previous state value
        const float yaw_angle = util::wrap(bicycle.pose().yaw);

        // calculate rider applied torque
        const float steer_torque = kistler_torque + mass_upper/mass_lower*(kistler_torque - motor_torque);

        // simulate bicycle
        bicycle.set_v(v);

        bicycle.update_dynamics(roll_torque, steer_torque, yaw_angle, steer_angle, rear_wheel_angle);

        // generate handlebar torque or velocity reference
#if defined(USE_BICYCLE_KINEMATIC_MODEL)
        const float desired_torque = haptic_drive.torque(model_t::get_state_part(bicycle.full_state()));
        const dacsample_t handlebar_reference_dac = sa::set_kollmorgen_torque(desired_torque);
#else // defined(USE_BICYCLE_KINEMATIC_MODEL)
        const float desired_velocity =
            model_t::get_full_state_element(bicycle.full_state(),
                                            model_t::full_state_index_t::steer_rate);
        const dacsample_t handlebar_reference_dac = sa::set_kollmorgen_velocity(desired_velocity);
#endif // defined(USE_BICYCLE_KINEMATIC_MODEL)
        chTMStopMeasurementX(&computation_time_measurement);

        {   // prepare message for transmission
            SimulationMessage* msg = transmitter.alloc_simulation_message();
            if (msg != nullptr) {
                *msg = SimulationMessage_init_zero;
                msg->timestamp = starttime;
                msg->model.v = bicycle.v();
                msg->model.has_v = true;
                msg->has_model = true;
                message::set_bicycle_input(
                        &msg->input,
                        (model_t::input_t() << roll_torque, steer_torque).finished());
                msg->has_input = true;
                message::set_simulation_state(msg, bicycle);
                message::set_simulation_auxiliary_state(msg, bicycle);
                message::set_simulation_actuators(msg, handlebar_reference_dac);
                message::set_simulation_sensors(
                        msg,
                        analog.get_adc12(),
                        analog.get_adc13(),
                        encoder_steer.count(),
                        encoder_rear_wheel.count());
                message::set_simulation_timing(
                        msg,
                        computation_time_measurement.last,
                        transmission_time_measurement.last);
                if (transmitter.transmit_async(msg) != MSG_OK) {
                    // Discard simulation message if it cannot be processed quickly enough.
                    transmitter.free_message(msg);
                }
            }
        }
        deadline = chThdSleepUntilWindowedOrYield(deadline, deadline + dynamics_loop_period);
    }
}
<|endoftext|>


<commit_before><commit_msg>Attempt at fixing crash when showing bookmark model. The crash indicates the node is null, which should only happen if adding the bookmark failed. Adding a bookmark can fail if the url isn't valid.<commit_after><|endoftext|>


<commit_before>#include "kwm.h"

extern std::vector<window_info> WindowLst;

node_container LeftVerticalContainerSplit(screen_info *Screen, tree_node *Node)
{
    node_container LeftContainer;

    LeftContainer.X = Node->Container.X;
    LeftContainer.Y = Node->Container.Y;
    LeftContainer.Width = (Node->Container.Width / 2) + (Screen->PaddingLeft / 2);
    LeftContainer.Height = Node->Container.Height;

    return LeftContainer;
}

node_container RightVerticalContainerSplit(screen_info *Screen, tree_node *Node)
{
    node_container RightContainer;

    RightContainer.X = Node->Container.X + (Node->Container.Width / 2) + (Screen->PaddingLeft);
    RightContainer.Y = Node->Container.Y;
    RightContainer.Width = (Node->Container.Width / 2) - (Screen->PaddingRight);
    RightContainer.Height = Node->Container.Height;

    return RightContainer;
}

node_container UpperHorizontalContainerSplit(screen_info *Screen, tree_node *Node)
{
    node_container UpperContainer;

    UpperContainer.X = Node->Container.X;
    UpperContainer.Y = Node->Container.Y;
    UpperContainer.Width = Node->Container.Width;
    UpperContainer.Height = (Node->Container.Height / 2);

    return UpperContainer;
}

node_container LowerHorizontalContainerSplit(screen_info *Screen, tree_node *Node)
{
    node_container LowerContainer;

    LowerContainer.X = Node->Container.X;
    LowerContainer.Y = Node->Container.Y + (Node->Container.Height / 2) + (Screen->PaddingBottom / 2);
    LowerContainer.Width = Node->Container.Width;
    LowerContainer.Height = (Node->Container.Height / 2) - (Screen->PaddingBottom / 2);

    return LowerContainer;
}

node_container FullscreenContainer(screen_info *Screen, tree_node *Node)
{
    node_container FullscreenContainer;

    FullscreenContainer.X = Node->Container.X;
    FullscreenContainer.Y = Node->Container.Y;
    FullscreenContainer.Width = Node->Container.Width - Screen->PaddingRight;
    FullscreenContainer.Height = Node->Container.Height;

    return FullscreenContainer;
}

tree_node *CreateLeafNode(screen_info *Screen, tree_node *Parent, int WindowID, int ContainerType)
{
    tree_node *Leaf = (tree_node*) malloc(sizeof(tree_node));
    Leaf->Parent = Parent;
    Leaf->WindowID = WindowID;

    switch(ContainerType)
    {
        case 0:
        {
            Leaf->Container = FullscreenContainer(Screen, Leaf->Parent);
        } break;
        case 1:
        {
            Leaf->Container = LeftVerticalContainerSplit(Screen, Leaf->Parent);
        } break;
        case 2:
        {
            Leaf->Container = RightVerticalContainerSplit(Screen, Leaf->Parent);
        } break;
        case 3:
        {
            Leaf->Container = UpperHorizontalContainerSplit(Screen, Leaf->Parent);
        } break;
        case 4:
        {
            Leaf->Container = LowerHorizontalContainerSplit(Screen, Leaf->Parent);
        } break;
    }

    Leaf->LeftChild = NULL;
    Leaf->RightChild = NULL;

    return Leaf;
}

tree_node *CreateRootNode()
{
    tree_node *RootNode = (tree_node*) malloc(sizeof(tree_node));
    std::memset(RootNode, '\0', sizeof(tree_node));

    RootNode->WindowID = -1;
    RootNode->Parent = NULL;
    RootNode->LeftChild = NULL;
    RootNode->RightChild = NULL;

    return RootNode;
}

void SetRootNodeContainer(tree_node *Node, int X, int Y, int Width, int Height)
{
    Node->Container.X = X;
    Node->Container.Y = Y,
    Node->Container.Width = Width;
    Node->Container.Height = Height;
}

void CreateLeafNodePair(screen_info *Screen, tree_node *Parent, int LeftWindowID, int RightWindowID, int SplitMode)
{
    if(SplitMode == 1)
    {
        Parent->LeftChild = CreateLeafNode(Screen, Parent, LeftWindowID, 1);
        Parent->RightChild = CreateLeafNode(Screen, Parent, RightWindowID, 2);
    }
    else
    {
        Parent->LeftChild = CreateLeafNode(Screen, Parent, LeftWindowID, 3);
        Parent->RightChild = CreateLeafNode(Screen, Parent, RightWindowID, 4);
    }
}

bool IsLeafNode(tree_node *Node)
{
    return Node->LeftChild == NULL && Node->RightChild == NULL ? true : false;
}

tree_node *CreateTreeFromWindowIDList(screen_info *Screen, std::vector<int> Windows)
{
    tree_node *RootNode = CreateRootNode();
    SetRootNodeContainer(RootNode, Screen->PaddingLeft, Screen->PaddingTop,
                         Screen->Width - Screen->PaddingLeft - Screen->PaddingRight,
                         Screen->Height - Screen->PaddingTop - Screen->PaddingBottom);

    if(Windows.size() == 1)
    {
        RootNode->WindowID = Windows[0];
    }
    else
    {
        int splitmode = 1;
        tree_node *Root = RootNode;
        Root->WindowID = Windows[0];
        for(int WindowIndex = 1; WindowIndex < Windows.size(); ++WindowIndex)
        {
            while(!IsLeafNode(Root))
            {
                if(!IsLeafNode(Root->LeftChild) && IsLeafNode(Root->RightChild))
                    Root = Root->RightChild;
                else
                    Root = Root->LeftChild;
            }

            DEBUG("CreateTreeFromWindowIDList() Create pair of leafs")
            CreateLeafNodePair(Screen, Root, Root->WindowID, Windows[WindowIndex], splitmode++ % 3);
            Root->WindowID = -1;
            Root = RootNode;
        }
    }

    return RootNode;
}

void SwapNodeWindowIDs(tree_node *A, tree_node *B)
{
    if(A && B)
    {
        DEBUG("SwapNodeWindowIDs() " << A->WindowID << " with " << B->WindowID)
        int TempWindowID = A->WindowID;
        A->WindowID = B->WindowID;
        B->WindowID = TempWindowID;
        ResizeWindow(A);
        ResizeWindow(B);
    }
}

tree_node *GetNodeFromWindowID(tree_node *Node, int WindowID)
{
    tree_node *Result = NULL;

    if(Node)
    {
        if(Node->WindowID == WindowID)
        {
            DEBUG("GetNodeFromWindowID() " << WindowID)
            return Node;
        }

        if(Node->LeftChild)
        {
            Result = GetNodeFromWindowID(Node->LeftChild, WindowID);
            if(Result == NULL)
                return GetNodeFromWindowID(Node->RightChild, WindowID);
        }

        if(Node->RightChild)
        {
            Result = GetNodeFromWindowID(Node->RightChild, WindowID);
            if(Result == NULL)
                return GetNodeFromWindowID(Node->LeftChild, WindowID);
        }
    }

    return Result;
}

tree_node *GetNearestNodeToTheLeft(tree_node *Node)
{
    if(Node)
    {
        if(Node->Parent)
        {
            tree_node *Root = Node->Parent;
            if(Root->LeftChild != Node)
            {
                if(Root->LeftChild->WindowID == -1)
                    return Root->LeftChild->RightChild;

                return Root->LeftChild;
            }
            else
            {
                return GetNearestNodeToTheLeft(Root);
            }
        }
    }

    return NULL;
}

tree_node *GetNearestNodeToTheRight(tree_node *Node)
{
    if(Node)
    {
        if(Node->Parent)
        {
            tree_node *Root = Node->Parent;
            if(Root->RightChild != Node)
            {
                if(Root->RightChild->WindowID == -1)
                    return Root->RightChild->LeftChild;

                return Root->RightChild;
            }
            else
            {
                return GetNearestNodeToTheRight(Root);
            }
        }
    }

    return NULL;
}

void ApplyNodeContainer(tree_node *Node)
{
    if(Node)
    {
        if(Node->LeftChild)
            ApplyNodeContainer(Node->LeftChild);

        if(Node->RightChild)
            ApplyNodeContainer(Node->RightChild);

        if(Node->WindowID != -1)
            ResizeWindow(Node);
    }
}

void DestroyNodeTree(tree_node *Node)
{
    if(Node)
    {
        if(Node->LeftChild)
            DestroyNodeTree(Node->LeftChild);

        if(Node->RightChild)
            DestroyNodeTree(Node->RightChild);

        free(Node);
    }
}
<commit_msg>should now once again work with multiple monitors<commit_after>#include "kwm.h"

extern std::vector<window_info> WindowLst;

node_container LeftVerticalContainerSplit(screen_info *Screen, tree_node *Node)
{
    node_container LeftContainer;

    LeftContainer.X = Node->Container.X;
    LeftContainer.Y = Node->Container.Y;
    LeftContainer.Width = (Node->Container.Width / 2) + (Screen->PaddingLeft / 2);
    LeftContainer.Height = Node->Container.Height;

    return LeftContainer;
}

node_container RightVerticalContainerSplit(screen_info *Screen, tree_node *Node)
{
    node_container RightContainer;

    RightContainer.X = Node->Container.X + (Node->Container.Width / 2) + (Screen->PaddingLeft);
    RightContainer.Y = Node->Container.Y;
    RightContainer.Width = (Node->Container.Width / 2) - (Screen->PaddingRight);
    RightContainer.Height = Node->Container.Height;

    return RightContainer;
}

node_container UpperHorizontalContainerSplit(screen_info *Screen, tree_node *Node)
{
    node_container UpperContainer;

    UpperContainer.X = Node->Container.X;
    UpperContainer.Y = Node->Container.Y;
    UpperContainer.Width = Node->Container.Width;
    UpperContainer.Height = (Node->Container.Height / 2);

    return UpperContainer;
}

node_container LowerHorizontalContainerSplit(screen_info *Screen, tree_node *Node)
{
    node_container LowerContainer;

    LowerContainer.X = Node->Container.X;
    LowerContainer.Y = Node->Container.Y + (Node->Container.Height / 2) + (Screen->PaddingBottom / 2);
    LowerContainer.Width = Node->Container.Width;
    LowerContainer.Height = (Node->Container.Height / 2) - (Screen->PaddingBottom / 2);

    return LowerContainer;
}

node_container FullscreenContainer(screen_info *Screen, tree_node *Node)
{
    node_container FullscreenContainer;

    FullscreenContainer.X = Node->Container.X;
    FullscreenContainer.Y = Node->Container.Y;
    FullscreenContainer.Width = Node->Container.Width - Screen->PaddingRight;
    FullscreenContainer.Height = Node->Container.Height;

    return FullscreenContainer;
}

tree_node *CreateLeafNode(screen_info *Screen, tree_node *Parent, int WindowID, int ContainerType)
{
    tree_node *Leaf = (tree_node*) malloc(sizeof(tree_node));
    Leaf->Parent = Parent;
    Leaf->WindowID = WindowID;

    switch(ContainerType)
    {
        case 0:
        {
            Leaf->Container = FullscreenContainer(Screen, Leaf->Parent);
        } break;
        case 1:
        {
            Leaf->Container = LeftVerticalContainerSplit(Screen, Leaf->Parent);
        } break;
        case 2:
        {
            Leaf->Container = RightVerticalContainerSplit(Screen, Leaf->Parent);
        } break;
        case 3:
        {
            Leaf->Container = UpperHorizontalContainerSplit(Screen, Leaf->Parent);
        } break;
        case 4:
        {
            Leaf->Container = LowerHorizontalContainerSplit(Screen, Leaf->Parent);
        } break;
    }

    Leaf->LeftChild = NULL;
    Leaf->RightChild = NULL;

    return Leaf;
}

tree_node *CreateRootNode()
{
    tree_node *RootNode = (tree_node*) malloc(sizeof(tree_node));
    std::memset(RootNode, '\0', sizeof(tree_node));

    RootNode->WindowID = -1;
    RootNode->Parent = NULL;
    RootNode->LeftChild = NULL;
    RootNode->RightChild = NULL;

    return RootNode;
}

void SetRootNodeContainer(tree_node *Node, int X, int Y, int Width, int Height)
{
    Node->Container.X = X;
    Node->Container.Y = Y,
    Node->Container.Width = Width;
    Node->Container.Height = Height;
}

void CreateLeafNodePair(screen_info *Screen, tree_node *Parent, int LeftWindowID, int RightWindowID, int SplitMode)
{
    if(SplitMode == 1)
    {
        Parent->LeftChild = CreateLeafNode(Screen, Parent, LeftWindowID, 1);
        Parent->RightChild = CreateLeafNode(Screen, Parent, RightWindowID, 2);
    }
    else
    {
        Parent->LeftChild = CreateLeafNode(Screen, Parent, LeftWindowID, 3);
        Parent->RightChild = CreateLeafNode(Screen, Parent, RightWindowID, 4);
    }
}

bool IsLeafNode(tree_node *Node)
{
    return Node->LeftChild == NULL && Node->RightChild == NULL ? true : false;
}

tree_node *CreateTreeFromWindowIDList(screen_info *Screen, std::vector<int> Windows)
{
    tree_node *RootNode = CreateRootNode();
    SetRootNodeContainer(RootNode, Screen->X + Screen->PaddingLeft, Screen->Y + Screen->PaddingTop,
                         Screen->Width - Screen->PaddingLeft - Screen->PaddingRight,
                         Screen->Height - Screen->PaddingTop - Screen->PaddingBottom);

    if(Windows.size() == 1)
    {
        RootNode->WindowID = Windows[0];
    }
    else
    {
        int splitmode = 1;
        tree_node *Root = RootNode;
        Root->WindowID = Windows[0];
        for(int WindowIndex = 1; WindowIndex < Windows.size(); ++WindowIndex)
        {
            while(!IsLeafNode(Root))
            {
                if(!IsLeafNode(Root->LeftChild) && IsLeafNode(Root->RightChild))
                    Root = Root->RightChild;
                else
                    Root = Root->LeftChild;
            }

            DEBUG("CreateTreeFromWindowIDList() Create pair of leafs")
            CreateLeafNodePair(Screen, Root, Root->WindowID, Windows[WindowIndex], splitmode++ % 3);
            Root->WindowID = -1;
            Root = RootNode;
        }
    }

    return RootNode;
}

void SwapNodeWindowIDs(tree_node *A, tree_node *B)
{
    if(A && B)
    {
        DEBUG("SwapNodeWindowIDs() " << A->WindowID << " with " << B->WindowID)
        int TempWindowID = A->WindowID;
        A->WindowID = B->WindowID;
        B->WindowID = TempWindowID;
        ResizeWindow(A);
        ResizeWindow(B);
    }
}

tree_node *GetNodeFromWindowID(tree_node *Node, int WindowID)
{
    tree_node *Result = NULL;

    if(Node)
    {
        if(Node->WindowID == WindowID)
        {
            DEBUG("GetNodeFromWindowID() " << WindowID)
            return Node;
        }

        if(Node->LeftChild)
        {
            Result = GetNodeFromWindowID(Node->LeftChild, WindowID);
            if(Result == NULL)
                return GetNodeFromWindowID(Node->RightChild, WindowID);
        }

        if(Node->RightChild)
        {
            Result = GetNodeFromWindowID(Node->RightChild, WindowID);
            if(Result == NULL)
                return GetNodeFromWindowID(Node->LeftChild, WindowID);
        }
    }

    return Result;
}

tree_node *GetNearestNodeToTheLeft(tree_node *Node)
{
    if(Node)
    {
        if(Node->Parent)
        {
            tree_node *Root = Node->Parent;
            if(Root->LeftChild != Node)
            {
                if(Root->LeftChild->WindowID == -1)
                    return Root->LeftChild->RightChild;

                return Root->LeftChild;
            }
            else
            {
                return GetNearestNodeToTheLeft(Root);
            }
        }
    }

    return NULL;
}

tree_node *GetNearestNodeToTheRight(tree_node *Node)
{
    if(Node)
    {
        if(Node->Parent)
        {
            tree_node *Root = Node->Parent;
            if(Root->RightChild != Node)
            {
                if(Root->RightChild->WindowID == -1)
                    return Root->RightChild->LeftChild;

                return Root->RightChild;
            }
            else
            {
                return GetNearestNodeToTheRight(Root);
            }
        }
    }

    return NULL;
}

void ApplyNodeContainer(tree_node *Node)
{
    if(Node)
    {
        if(Node->LeftChild)
            ApplyNodeContainer(Node->LeftChild);

        if(Node->RightChild)
            ApplyNodeContainer(Node->RightChild);

        if(Node->WindowID != -1)
            ResizeWindow(Node);
    }
}

void DestroyNodeTree(tree_node *Node)
{
    if(Node)
    {
        if(Node->LeftChild)
            DestroyNodeTree(Node->LeftChild);

        if(Node->RightChild)
            DestroyNodeTree(Node->RightChild);

        free(Node);
    }
}
<|endoftext|>


<commit_before>#include "p0run/default_garbage_collector.hpp"
#include "p0run/object.hpp"
#include <boost/test/unit_test.hpp>
#include <boost/foreach.hpp>
#include <algorithm>
using namespace p0::run;

BOOST_AUTO_TEST_CASE(default_gc_test)
{
	typedef int vector_safe_bool;

	struct gc_tester PROTOLANG0_FINAL_CLASS : p0::run::object
	{
		explicit gc_tester(vector_safe_bool &is_alive)
			: m_is_alive(is_alive)
		{
			m_is_alive = true;
		}

		virtual ~gc_tester()
		{
			m_is_alive = false;
		}

	private:

		vector_safe_bool &m_is_alive;

		virtual void mark_recursively() PROTOLANG0_FINAL_METHOD
		{
		}
	};

	p0::run::default_garbage_collector gc;

	std::vector<vector_safe_bool> alive_status(64);
	std::vector<p0::run::object *> test_objects;

	BOOST_FOREACH (auto &is_alive, alive_status)
	{
		test_objects.push_back(
					&construct_object<gc_tester>(gc, is_alive));
	}

	//all created objects are expected to be alive before garbage collection
	BOOST_CHECK(std::all_of(alive_status.begin(),
							alive_status.end(),
							[](bool a) { return a; }));

	//not strictly required here, but called in practice before marking
	gc.unmark();

	//mark the first half of the objects as required to be alive
	std::for_each(test_objects.begin(),
				  test_objects.begin() + test_objects.size() / 2,
				  [](p0::run::object *object)
	{
		object->mark();
	});

	//let the gc destroy unneeded objects
	gc.sweep(p0::run::sweep_mode::full);

	//the marked half is expected to be still alive
	BOOST_CHECK(std::all_of(alive_status.begin(),
							alive_status.begin() + alive_status.size() / 2,
							[](bool a) { return a; }));

	//the half not marked is expected to not be alive after sweep
	BOOST_CHECK(std::all_of(alive_status.begin() + alive_status.size() / 2,
							alive_status.end(),
							[](bool a) { return !a; }));
}
<commit_msg>test gc dependency cycles<commit_after>#include "p0run/default_garbage_collector.hpp"
#include "p0run/object.hpp"
#include <boost/test/unit_test.hpp>
#include <boost/foreach.hpp>
#include <algorithm>
#include <array>
using namespace p0::run;

namespace
{
	typedef int vector_safe_bool;

	struct gc_tester : p0::run::object
	{
		explicit gc_tester(vector_safe_bool &is_alive)
			: m_is_alive(is_alive)
		{
			m_is_alive = true;
		}

		virtual ~gc_tester()
		{
			m_is_alive = false;
		}

	private:

		vector_safe_bool &m_is_alive;

		virtual void mark_recursively() PROTOLANG0_OVERRIDE
		{
		}
	};
}

BOOST_AUTO_TEST_CASE(default_gc_test)
{
	p0::run::default_garbage_collector gc;

	std::vector<vector_safe_bool> alive_status(64);
	std::vector<p0::run::object *> test_objects;

	BOOST_FOREACH (auto &is_alive, alive_status)
	{
		test_objects.push_back(
					&construct_object<gc_tester>(gc, is_alive));
	}

	//all created objects are expected to be alive before garbage collection
	BOOST_CHECK(std::all_of(alive_status.begin(),
							alive_status.end(),
							[](bool a) { return a; }));

	//not strictly required here, but called in practice before marking
	gc.unmark();

	//mark the first half of the objects as required to be alive
	std::for_each(test_objects.begin(),
				  test_objects.begin() + test_objects.size() / 2,
				  [](p0::run::object *object)
	{
		object->mark();
	});

	//let the gc destroy unneeded objects
	gc.sweep(p0::run::sweep_mode::full);

	//the marked half is expected to be still alive
	BOOST_CHECK(std::all_of(alive_status.begin(),
							alive_status.begin() + alive_status.size() / 2,
							[](bool a) { return a; }));

	//the half not marked is expected to not be alive after sweep
	BOOST_CHECK(std::all_of(alive_status.begin() + alive_status.size() / 2,
							alive_status.end(),
							[](bool a) { return !a; }));
}

namespace
{
	struct referencing_gc_tester PROTOLANG0_FINAL_CLASS : gc_tester
	{
		p0::run::value reference;

		referencing_gc_tester(vector_safe_bool &is_alive)
			: gc_tester(is_alive)
		{
		}

	private:

		virtual void mark_recursively() PROTOLANG0_FINAL_METHOD
		{
			mark_value(reference);
		}
	};

	bool test_dependency_cycle(size_t cycle_length, bool is_marked)
	{
		p0::run::default_garbage_collector gc;
		std::vector<vector_safe_bool> is_alive(cycle_length);
		{
			std::vector<referencing_gc_tester *> test_objects(cycle_length);
			for (size_t i = 0; i < is_alive.size(); ++i)
			{
				test_objects[i] = &dynamic_cast<referencing_gc_tester &>(
					construct_object<referencing_gc_tester>(gc, is_alive[i]));
			}
			for (size_t i = 0; i < test_objects.size(); ++i)
			{
				test_objects[i]->reference = p0::run::value(
							*test_objects[(i + 1) % test_objects.size()]);
			}
			gc.unmark();
			if (is_marked)
			{
				test_objects.front()->mark();
			}
		}
		gc.sweep(p0::run::sweep_mode::full);
		return std::count(begin(is_alive), end(is_alive), !is_marked) == 0;
	}
}

BOOST_AUTO_TEST_CASE(default_gc_cycle_test)
{
	BOOST_CHECK(test_dependency_cycle(1, true));
	BOOST_CHECK(test_dependency_cycle(2, true));
	BOOST_CHECK(test_dependency_cycle(3, true));
	BOOST_CHECK(test_dependency_cycle(4, true));
	BOOST_CHECK(test_dependency_cycle(20, true));

	BOOST_CHECK(test_dependency_cycle(1, false));
	BOOST_CHECK(test_dependency_cycle(2, false));
	BOOST_CHECK(test_dependency_cycle(3, false));
	BOOST_CHECK(test_dependency_cycle(4, false));
	BOOST_CHECK(test_dependency_cycle(20, false));
}
<|endoftext|>


<commit_before>// @@@ START COPYRIGHT @@@
//
// Licensed to the Apache Software Foundation (ASF) under one
// or more contributor license agreements.  See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership.  The ASF licenses this file
// to you under the Apache License, Version 2.0 (the
// "License"); you may not use this file except in compliance
// with the License.  You may obtain a copy of the License at
//
//   http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing,
// software distributed under the License is distributed on an
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
// KIND, either express or implied.  See the License for the
// specific language governing permissions and limitations
// under the License.
//
// @@@ END COPYRIGHT @@@

#include "HbaseSearchSpec.h"
#include "ItemColRef.h"

void HbaseSearchSpec::addColumnNames(const ValueIdSet& vs)
{
  // TEMP TEMP. Not all needed column names are being set up.
  // for now, return without populating result.
  // that will cause all columns to be retrieved.
  //return;

   for (ValueId vid = vs.init(); vs.next(vid); vs.advance(vid)) {
      ItemExpr* ie = vid.getItemExpr();

      NAString colName;
      if ( ie->getOperatorType() == ITM_BASECOLUMN ) {
	colName = ((BaseColumn*)ie)->getColName();
      } else
	if ( ie->getOperatorType() == ITM_INDEXCOLUMN ) {
	  colName = ((IndexColumn*)ie)->getNAColumn()->getIndexColName();
	}

      if (NOT colNames_.contains(colName))
	colNames_.insert(colName);
   }
}

const NAString HbaseSearchSpec::getText() const
{
   if ( colNames_.entries() == 0 )
     return "columns: all ";

   NAString result("columns: ");
   for ( CollIndex i=0; i<colNames_.entries(); i++ ) {
      result.append(colNames_[i]);

      if (i < colNames_.entries() - 1)
         result.append(",");
   }

   result.append(" ");
   return result;
}

static NABoolean extractKeyValuePairs(const NAString& source, NAString& result);

const NAString HbaseUniqueRows::getText() const
{
   NAString result = HbaseSearchSpec::getText();

   for ( CollIndex i=0; i<rowIds_.entries(); i++ ) {

      result.append("unique_rows: ");
      extractKeyValuePairs(rowIds_[i], result);
      result.append(" ");
   }

   return result;
}

//
// data (begin or end) is in this format:
//  <length><data> ... <length><data>
//
// a). length is 2-bytes long
// b). data is <length>-bytes long
// c). there are <n> such pairs, where <n> is determined by
//     the total length of the source and the length of each pair.
//
static NABoolean extractKeyValuePairs(const NAString& source, NAString& result)
{
   char buf[1024];

   const char* data = source.data();
   const char* end = data + source.length();

   NABoolean hasData = ( data < end);

   while ( data < end ) {
       UInt16 len = 0;
       memcpy((char*)&len, data, sizeof(len));

       memcpy(buf, data+sizeof(len), len);
       buf[len] = NULL;

       result.append(buf);

       data += sizeof(len) + len;

       if ( data < end )
          result.append(",");
   }
   return hasData;
}

const NAString HbaseRangeRows::getText() const
{
   NAString result = HbaseSearchSpec::getText();

   result.append("begin_keys");
   result.append(beginKeyExclusive_ ? "(excl)" : "(incl)");
   result.append(": ");

   // rowId_ (begin or end) is in this format:
   //  <length><data> ... <length><data>
   //
   // a). length is 2-bytes long
   // b). data is <length> bytes long
   // c). there are <n> such pairs, where <n> is determined by
   //     the total length of the data and the length of each pair.

   extractKeyValuePairs(beginRowId_, result);

   result.append(" ");

   result.append("end_keys");
   result.append(endKeyExclusive_ ? "(excl)" : "(incl)");
   result.append(": ");

   extractKeyValuePairs(endRowId_, result);

   result.append(" ");

   return result;
}

const NAString ListOfUniqueRows::getText() const
{
  NAString result;
  for (CollIndex i=0; i<entries(); i++) {
     HbaseUniqueRows getRow = (*this)[i];
     result.append(getRow.getText());
  }
  return result;
}

const NAString ListOfRangeRows::getText() const
{
  NAString result;
  for (CollIndex i=0; i<entries(); i++) {
     HbaseRangeRows rangeRow = (*this)[i];
     result.append(rangeRow.getText());
  }
  return result;
}

<commit_msg>[TRAFODION-2675] Fix sqlci core dump issue.<commit_after>// @@@ START COPYRIGHT @@@
//
// Licensed to the Apache Software Foundation (ASF) under one
// or more contributor license agreements.  See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership.  The ASF licenses this file
// to you under the Apache License, Version 2.0 (the
// "License"); you may not use this file except in compliance
// with the License.  You may obtain a copy of the License at
//
//   http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing,
// software distributed under the License is distributed on an
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
// KIND, either express or implied.  See the License for the
// specific language governing permissions and limitations
// under the License.
//
// @@@ END COPYRIGHT @@@

#include "HbaseSearchSpec.h"
#include "ItemColRef.h"

void HbaseSearchSpec::addColumnNames(const ValueIdSet& vs)
{
  // TEMP TEMP. Not all needed column names are being set up.
  // for now, return without populating result.
  // that will cause all columns to be retrieved.
  //return;

   for (ValueId vid = vs.init(); vs.next(vid); vs.advance(vid)) {
      ItemExpr* ie = vid.getItemExpr();

      NAString colName;
      if ( ie->getOperatorType() == ITM_BASECOLUMN ) {
	colName = ((BaseColumn*)ie)->getColName();
      } else
	if ( ie->getOperatorType() == ITM_INDEXCOLUMN ) {
	  colName = ((IndexColumn*)ie)->getNAColumn()->getIndexColName();
	}

      if (NOT colNames_.contains(colName))
	colNames_.insert(colName);
   }
}

const NAString HbaseSearchSpec::getText() const
{
   if ( colNames_.entries() == 0 )
     return "columns: all ";

   NAString result("columns: ");
   for ( CollIndex i=0; i<colNames_.entries(); i++ ) {
      result.append(colNames_[i]);

      if (i < colNames_.entries() - 1)
         result.append(",");
   }

   result.append(" ");
   return result;
}

static NABoolean extractKeyValuePairs(const NAString& source, NAString& result);

const NAString HbaseUniqueRows::getText() const
{
   NAString result = HbaseSearchSpec::getText();

   for ( CollIndex i=0; i<rowIds_.entries(); i++ ) {

      result.append("unique_rows: ");
      extractKeyValuePairs(rowIds_[i], result);
      result.append(" ");
   }

   return result;
}

//
// data (begin or end) is in this format:
//  <length><data> ... <length><data>
//
// a). length is 2-bytes long
// b). data is <length>-bytes long
// c). there are <n> such pairs, where <n> is determined by
//     the total length of the source and the length of each pair.
//
static NABoolean extractKeyValuePairs(const NAString& source, NAString& result)
  {
    UInt16 typeLen = sizeof(UInt16);
    size_t header = 0;
    size_t tail = source.length();
    NABoolean hasData = ( tail > 0 );

    const char* data = source.data();

    while ( header < tail ){
      // get the length of the string
      size_t begin = header;
      size_t end = begin + typeLen;
      // error, do not have enough buffer to read
      if ( end > tail )
        break;
      NAString len;
      source.extract(begin, end-1, len);

      // get the string
      begin = end;
      end = begin + (*(UInt16 *)(len.data()));
      // if the string lengh is 0, continue
      if ( end == begin) {
        header = end;
        if ( header < tail )
          result.append(",");
        continue;
      }
      // error, do not have enough buffer to read
      else if ( end > tail )
        break;
      source.extract(begin, end-1, result);
      header = end;
      if ( header < tail )
        result.append(",");
    }

    return hasData;
  }

const NAString HbaseRangeRows::getText() const
{
   NAString result = HbaseSearchSpec::getText();

   result.append("begin_keys");
   result.append(beginKeyExclusive_ ? "(excl)" : "(incl)");
   result.append(": ");

   // rowId_ (begin or end) is in this format:
   //  <length><data> ... <length><data>
   //
   // a). length is 2-bytes long
   // b). data is <length> bytes long
   // c). there are <n> such pairs, where <n> is determined by
   //     the total length of the data and the length of each pair.

   extractKeyValuePairs(beginRowId_, result);

   result.append(" ");

   result.append("end_keys");
   result.append(endKeyExclusive_ ? "(excl)" : "(incl)");
   result.append(": ");

   extractKeyValuePairs(endRowId_, result);

   result.append(" ");

   return result;
}

const NAString ListOfUniqueRows::getText() const
{
  NAString result;
  for (CollIndex i=0; i<entries(); i++) {
     HbaseUniqueRows getRow = (*this)[i];
     result.append(getRow.getText());
  }
  return result;
}

const NAString ListOfRangeRows::getText() const
{
  NAString result;
  for (CollIndex i=0; i<entries(); i++) {
     HbaseRangeRows rangeRow = (*this)[i];
     result.append(rangeRow.getText());
  }
  return result;
}

<|endoftext|>


<commit_before>//---------------------------------------------------------------------------//
/*
  Copyright (c) 2012, Stuart R. Slattery
  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 of conditions 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 materials provided with the distribution.

  *: Neither the name of the University of Wisconsin - Madison nor the
  names of its contributors may be used to endorse or promote products
  derived from this software without specific prior written permission.

  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.
*/
//---------------------------------------------------------------------------//
/*!
 * \file tstTpetraDomainCommunicator.cpp
 * \author Stuart R. Slattery
 * \brief Tpetra DomainCommunicator tests.
 */
//---------------------------------------------------------------------------//

#include <stack>
#include <iostream>
#include <vector>
#include <cmath>
#include <cstdlib>
#include <sstream>
#include <algorithm>
#include <string>
#include <cassert>

#include <MCLS_DomainCommunicator.hpp>
#include <MCLS_DomainTransporter.hpp>
#include <MCLS_AdjointDomain.hpp>
#include <MCLS_VectorTraits.hpp>
#include <MCLS_TpetraAdapter.hpp>
#include <MCLS_AdjointHistory.hpp>
#include <MCLS_AdjointTally.hpp>
#include <MCLS_Events.hpp>

#include <Teuchos_UnitTestHarness.hpp>
#include <Teuchos_DefaultComm.hpp>
#include <Teuchos_CommHelpers.hpp>
#include <Teuchos_RCP.hpp>
#include <Teuchos_ArrayRCP.hpp>
#include <Teuchos_Array.hpp>
#include <Teuchos_ArrayView.hpp>
#include <Teuchos_TypeTraits.hpp>
#include <Teuchos_ParameterList.hpp>

#include <Tpetra_Map.hpp>
#include <Tpetra_Vector.hpp>

//---------------------------------------------------------------------------//
// Instantiation macro.
//
// These types are those enabled by Tpetra under explicit instantiation. I
// have removed scalar types that are not floating point
//---------------------------------------------------------------------------//
#define UNIT_TEST_INSTANTIATION( type, name )			           \
    TEUCHOS_UNIT_TEST_TEMPLATE_3_INSTANT( type, name, int, long, double )

//---------------------------------------------------------------------------//
// Helper functions.
//---------------------------------------------------------------------------//
template<class GO>
Teuchos::RCP<MCLS::AdjointHistory<GO> > makeHistory(
    GO state, double weight, int streamid )
{
    Teuchos::RCP<MCLS::AdjointHistory<GO> > history = Teuchos::rcp(
	new MCLS::AdjointHistory<GO>( state, state, weight ) );
    history->setEvent( MCLS::Event::BOUNDARY );
    return history;
}

//---------------------------------------------------------------------------//
// Test templates
//---------------------------------------------------------------------------//
TEUCHOS_UNIT_TEST_TEMPLATE_3_DECL( DomainCommunicator, Typedefs, LO, GO, Scalar )
{
    typedef Tpetra::Vector<Scalar,LO,GO> VectorType;
    typedef Tpetra::CrsMatrix<Scalar,LO,GO> MatrixType;
    typedef MCLS::AdjointDomain<VectorType,MatrixType,std::mt19937> DomainType;
    typedef MCLS::AdjointHistory<GO> HistoryType;

    typedef MCLS::DomainTransporter<DomainType> TransportType;
    typedef typename TransportType::HistoryType history_type;
    typedef typename TransportType::BankType bank_type;

    TEST_EQUALITY_CONST(
	(Teuchos::TypeTraits::is_same<HistoryType, history_type>::value)
	== true, true );
    TEST_EQUALITY_CONST(
	(Teuchos::TypeTraits::is_same<bank_type,
	 std::stack<Teuchos::RCP<HistoryType> > >::value)
	 == true, true );
}

UNIT_TEST_INSTANTIATION( DomainCommunicator, Typedefs )

//---------------------------------------------------------------------------//
TEUCHOS_UNIT_TEST_TEMPLATE_3_DECL( DomainCommunicator, Communicate, LO, GO, Scalar )
{
    typedef Tpetra::Vector<Scalar,LO,GO> VectorType;
    typedef Tpetra::CrsMatrix<Scalar,LO,GO> MatrixType;
    typedef MCLS::MatrixTraits<VectorType,MatrixType> MT;
    typedef MCLS::AdjointHistory<GO> HistoryType;
    typedef std::mt19937 rng_type;
    typedef MCLS::AdjointDomain<VectorType,MatrixType,rng_type> DomainType;

    Teuchos::RCP<const Teuchos::Comm<int> > comm =
	Teuchos::DefaultComm<int>::getComm();
    int comm_size = comm->getSize();
    int comm_rank = comm->getRank();

    // This test is parallel.
    if ( comm_size > 1 )
    {
	int local_num_rows = 10;
	int global_num_rows = local_num_rows*comm_size;
	Teuchos::RCP<const Tpetra::Map<LO,GO> > map =
	    Tpetra::createUniformContigMap<LO,GO>( global_num_rows, comm );

	// Build the linear operator and solution vector.
	Teuchos::RCP<MatrixType> A = Tpetra::createCrsMatrix<Scalar,LO,GO>( map );
	Teuchos::Array<GO> global_columns( 1 );
	Teuchos::Array<Scalar> values( 1 );
	for ( int i = 1; i < global_num_rows; ++i )
	{
	    global_columns[0] = i-1;
	    values[0] = -0.5/comm_size;
	    A->insertGlobalValues( i, global_columns(), values() );
	}
	global_columns[0] = global_num_rows-1;
	values[0] = -0.5/comm_size;
	A->insertGlobalValues( global_num_rows-1, global_columns(), values() );
	A->fillComplete();

	Teuchos::RCP<VectorType> x = MT::cloneVectorFromMatrixRows( *A );
        Teuchos::RCP<MatrixType> A_T = MT::copyTranspose(*A);

	// Build the adjoint domain.
	Teuchos::ParameterList plist;
	plist.set<int>( "Overlap Size", 0 );
	Teuchos::RCP<DomainType> domain =
            Teuchos::rcp( new DomainType( A_T, x, plist ) );
	Teuchos::RCP<MCLS::PRNG<rng_type> > rng = Teuchos::rcp(
	    new MCLS::PRNG<rng_type>( comm->getRank() ) );
	domain->setRNG( rng );

	// History setup.
	HistoryType::setByteSize();

	// Build the domain communicator.
	typename MCLS::DomainCommunicator<DomainType>::BankType bank;
	int buffer_size = 3;
	plist.set<int>( "MC Buffer Size", buffer_size );
	MCLS::DomainCommunicator<DomainType> communicator( domain, comm, plist );

	// Test initialization.
	TEST_EQUALITY( Teuchos::as<int>(communicator.maxBufferSize()), buffer_size );
	TEST_ASSERT( !communicator.sendStatus() );
	TEST_ASSERT( !communicator.receiveStatus() );

	// Post receives.
	communicator.post();
	if ( comm_rank == 0 )
	{
	    TEST_ASSERT( !communicator.receiveStatus() );
	}
	else
	{
	    TEST_ASSERT( communicator.receiveStatus() );
	}

	// End communication.
	communicator.end();
	TEST_ASSERT( !communicator.receiveStatus() );

	// Post new receives.
	communicator.post();
	if ( comm_rank == 0 )
	{
	    TEST_ASSERT( !communicator.receiveStatus() );
	}
	else
	{
	    TEST_ASSERT( communicator.receiveStatus() );
	}
	TEST_EQUALITY( communicator.sendBufferSize(), 0 );

	// Flush with zero histories.
	TEST_EQUALITY( communicator.flush(), 0 );
	if ( comm_rank == 0 )
	{
	    TEST_ASSERT( !communicator.receiveStatus() );
	}
	else
	{
	    TEST_ASSERT( communicator.receiveStatus() );
	}
	TEST_ASSERT( !communicator.sendStatus() );

	// Receive empty flushed buffers.
	int zero_histories = communicator.wait( bank );
	TEST_EQUALITY( zero_histories, 0 );
	TEST_ASSERT( !communicator.receiveStatus() );
	TEST_ASSERT( bank.empty() );

	// Repost receives.
	communicator.post();
	if ( comm_rank == 0 )
	{
	    TEST_ASSERT( !communicator.receiveStatus() );
	}
	else
	{
	    TEST_ASSERT( communicator.receiveStatus() );
	}

	// Proc 0 will send to proc 1.
	if ( comm_rank == 0 )
	{
	    TEST_ASSERT( !domain->isGlobalState(10) );

	    Teuchos::RCP<HistoryType> h1 =
		makeHistory<GO>( 10, 1.1, comm_rank*4 + 1 );
	    const typename MCLS::DomainCommunicator<DomainType>::Result
		r1 = communicator.communicate( h1 );
	    TEST_ASSERT( !r1.sent );
	    TEST_EQUALITY( communicator.sendBufferSize(), 1 );

	    Teuchos::RCP<HistoryType> h2 =
		makeHistory<GO>( 10, 2.1, comm_rank*4 + 2 );
	    const typename MCLS::DomainCommunicator<DomainType>::Result
		r2 = communicator.communicate( h2 );
	    TEST_ASSERT( !r2.sent );
	    TEST_EQUALITY( communicator.sendBufferSize(), 2 );

	    Teuchos::RCP<HistoryType> h3 =
		makeHistory<GO>( 10, 3.1, comm_rank*4 + 3 );
	    const typename MCLS::DomainCommunicator<DomainType>::Result
		r3 = communicator.communicate( h3 );
	    TEST_ASSERT( r3.sent );
	    TEST_EQUALITY( r3.destination, 1 );
	    TEST_EQUALITY( communicator.sendBufferSize(), 0 );
	}

	// Proc comm_rank send to proc comm_rank+1 and receive from proc
	// comm_rank-1.
	else if ( comm_rank < comm_size - 1 )
	{
	    // Send to proc comm_rank+1.
	    TEST_ASSERT( !domain->isGlobalState((comm_rank+1)*10) );

	    Teuchos::RCP<HistoryType> h1 =
		makeHistory<GO>( (comm_rank+1)*10, 1.1, comm_rank*4 + 1 );
	    const typename MCLS::DomainCommunicator<DomainType>::Result
		r1 = communicator.communicate( h1 );
	    TEST_ASSERT( !r1.sent );
	    TEST_EQUALITY( communicator.sendBufferSize(), 1 );

	    Teuchos::RCP<HistoryType> h2 =
		makeHistory<GO>( (comm_rank+1)*10, 2.1, comm_rank*4 + 2 );
	    const typename MCLS::DomainCommunicator<DomainType>::Result
		r2 = communicator.communicate( h2 );
	    TEST_ASSERT( !r2.sent );
	    TEST_EQUALITY( communicator.sendBufferSize(), 2 );

	    Teuchos::RCP<HistoryType> h3 =
		makeHistory<GO>( (comm_rank+1)*10, 3.1, comm_rank*4 + 3 );
	    const typename MCLS::DomainCommunicator<DomainType>::Result
		r3 = communicator.communicate( h3 );
	    TEST_ASSERT( r3.sent );
	    TEST_EQUALITY( r3.destination, comm_rank+1 );
	    TEST_EQUALITY( communicator.sendBufferSize(), 0 );

	    // Receive from proc comm_rank-1.
	    while ( bank.empty() )
	    {
		communicator.checkAndPost( bank );
	    }

	    TEST_EQUALITY( bank.size(), 3 );

	    Teuchos::RCP<HistoryType> rp3 = bank.top();
	    bank.pop();
	    Teuchos::RCP<HistoryType> rp2 = bank.top();
	    bank.pop();
	    Teuchos::RCP<HistoryType> rp1 = bank.top();
	    bank.pop();
	    TEST_ASSERT( bank.empty() );

	    TEST_EQUALITY( rp3->globalState(), comm_rank*10 );
	    TEST_EQUALITY( rp3->weight(), 3.1 );
	    TEST_EQUALITY( rp2->globalState(), comm_rank*10 );
	    TEST_EQUALITY( rp2->weight(), 2.1 );
	    TEST_EQUALITY( rp1->globalState(), comm_rank*10 );
	    TEST_EQUALITY( rp1->weight(), 1.1 );

	    TEST_ASSERT( communicator.receiveStatus() );
	}

	// The last proc just receives.
	else
	{
	    // Check and post until receive from proc comm_rank-1
	    while ( bank.empty() )
	    {
		communicator.checkAndPost( bank );
	    }
	    TEST_ASSERT( communicator.receiveStatus() );
	    TEST_EQUALITY( bank.size(), 3 );

	    Teuchos::RCP<HistoryType> rp3 = bank.top();
	    bank.pop();
	    Teuchos::RCP<HistoryType> rp2 = bank.top();
	    bank.pop();
	    Teuchos::RCP<HistoryType> rp1 = bank.top();
	    bank.pop();
	    TEST_ASSERT( bank.empty() );

	    TEST_EQUALITY( rp3->globalState(), comm_rank*10 );
	    TEST_EQUALITY( rp3->weight(), 3.1 );
	    TEST_EQUALITY( rp2->globalState(), comm_rank*10 );
	    TEST_EQUALITY( rp2->weight(), 2.1 );
	    TEST_EQUALITY( rp1->globalState(), comm_rank*10 );
	    TEST_EQUALITY( rp1->weight(), 1.1 );
	}

	// End communication.
	communicator.end();
	TEST_ASSERT( !communicator.receiveStatus() );
    }

    // Barrier before exiting to make sure memory deallocation happened
    // correctly.
    comm->barrier();
}

UNIT_TEST_INSTANTIATION( DomainCommunicator, Communicate )

//---------------------------------------------------------------------------//
// end tstTpetraDomainCommunicator.cpp
//---------------------------------------------------------------------------//

<commit_msg>updating tpetra domain communicator test<commit_after>//---------------------------------------------------------------------------//
/*
  Copyright (c) 2012, Stuart R. Slattery
  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 of conditions 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 materials provided with the distribution.

  *: Neither the name of the University of Wisconsin - Madison nor the
  names of its contributors may be used to endorse or promote products
  derived from this software without specific prior written permission.

  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.
*/
//---------------------------------------------------------------------------//
/*!
 * \file tstTpetraDomainCommunicator.cpp
 * \author Stuart R. Slattery
 * \brief Tpetra DomainCommunicator tests.
 */
//---------------------------------------------------------------------------//

#include <stack>
#include <iostream>
#include <vector>
#include <cmath>
#include <cstdlib>
#include <sstream>
#include <algorithm>
#include <string>
#include <cassert>

#include <MCLS_DomainCommunicator.hpp>
#include <MCLS_DomainTransporter.hpp>
#include <MCLS_AlmostOptimalDomain.hpp>
#include <MCLS_VectorTraits.hpp>
#include <MCLS_TpetraAdapter.hpp>
#include <MCLS_AdjointHistory.hpp>
#include <MCLS_AdjointTally.hpp>
#include <MCLS_Events.hpp>

#include <Teuchos_UnitTestHarness.hpp>
#include <Teuchos_DefaultComm.hpp>
#include <Teuchos_CommHelpers.hpp>
#include <Teuchos_RCP.hpp>
#include <Teuchos_ArrayRCP.hpp>
#include <Teuchos_Array.hpp>
#include <Teuchos_ArrayView.hpp>
#include <Teuchos_TypeTraits.hpp>
#include <Teuchos_ParameterList.hpp>

#include <Tpetra_Map.hpp>
#include <Tpetra_Vector.hpp>

//---------------------------------------------------------------------------//
// Helper functions.
//---------------------------------------------------------------------------//
Teuchos::RCP<MCLS::AdjointHistory<long> > makeHistory(
    long state, double weight, int streamid )
{
    Teuchos::RCP<MCLS::AdjointHistory<long> > history = Teuchos::rcp(
	new MCLS::AdjointHistory<long>( state, state, weight ) );
    history->setEvent( MCLS::Event::BOUNDARY );
    return history;
}

//---------------------------------------------------------------------------//
// Test templates
//---------------------------------------------------------------------------//
TEUCHOS_UNIT_TEST( DomainCommunicator, Communicate )
{
    typedef Tpetra::Vector<double,int,long> VectorType;
    typedef Tpetra::CrsMatrix<double,int,long> MatrixType;
    typedef MCLS::MatrixTraits<VectorType,MatrixType> MT;
    typedef MCLS::AdjointHistory<long> HistoryType;
    typedef std::mt19937 rng_type;
    typedef MCLS::AdjointTally<VectorType> TallyType;
    typedef MCLS::AlmostOptimalDomain<VectorType,MatrixType,rng_type,TallyType>
	DomainType;

    Teuchos::RCP<const Teuchos::Comm<int> > comm =
	Teuchos::DefaultComm<int>::getComm();
    int comm_size = comm->getSize();
    int comm_rank = comm->getRank();

    // This test is parallel.
    if ( comm_size > 1 )
    {
	int local_num_rows = 10;
	int global_num_rows = local_num_rows*comm_size;
	Teuchos::RCP<const Tpetra::Map<int,long> > map =
	    Tpetra::createUniformContigMap<int,long>( global_num_rows, comm );

	// Build the linear operator and solution vector.
	Teuchos::RCP<MatrixType> A = Tpetra::createCrsMatrix<double,int,long>( map );
	Teuchos::Array<long> global_columns( 1 );
	Teuchos::Array<double> values( 1 );
	for ( int i = 1; i < global_num_rows; ++i )
	{
	    global_columns[0] = i-1;
	    values[0] = -0.5/comm_size;
	    A->insertGlobalValues( i, global_columns(), values() );
	}
	global_columns[0] = global_num_rows-1;
	values[0] = -0.5/comm_size;
	A->insertGlobalValues( global_num_rows-1, global_columns(), values() );
	A->fillComplete();

	Teuchos::RCP<VectorType> x = MT::cloneVectorFromMatrixRows( *A );
        Teuchos::RCP<MatrixType> A_T = MT::copyTranspose(*A);

	// Build the adjoint domain.
	Teuchos::ParameterList plist;
	plist.set<int>( "Overlap Size", 0 );
	Teuchos::RCP<DomainType> domain =
            Teuchos::rcp( new DomainType( A_T, x, plist ) );
	Teuchos::RCP<MCLS::PRNG<rng_type> > rng = Teuchos::rcp(
	    new MCLS::PRNG<rng_type>( comm->getRank() ) );
	domain->setRNG( rng );

	// History setup.
	HistoryType::setByteSize();

	// Build the domain communicator.
	typename MCLS::DomainCommunicator<DomainType>::BankType bank;
	int buffer_size = 3;
	plist.set<int>( "MC Buffer Size", buffer_size );
	MCLS::DomainCommunicator<DomainType> communicator( domain, comm, plist );

	// Test initialization.
	TEST_EQUALITY( Teuchos::as<int>(communicator.maxBufferSize()), buffer_size );
	TEST_ASSERT( !communicator.sendStatus() );
	TEST_ASSERT( !communicator.receiveStatus() );

	// Post receives.
	communicator.post();
	if ( comm_rank == 0 )
	{
	    TEST_ASSERT( !communicator.receiveStatus() );
	}
	else
	{
	    TEST_ASSERT( communicator.receiveStatus() );
	}

	// End communication.
	communicator.end();
	TEST_ASSERT( !communicator.receiveStatus() );

	// Post new receives.
	communicator.post();
	if ( comm_rank == 0 )
	{
	    TEST_ASSERT( !communicator.receiveStatus() );
	}
	else
	{
	    TEST_ASSERT( communicator.receiveStatus() );
	}
	TEST_EQUALITY( communicator.sendBufferSize(), 0 );

	// Flush with zero histories.
	TEST_EQUALITY( communicator.flush(), 0 );
	if ( comm_rank == 0 )
	{
	    TEST_ASSERT( !communicator.receiveStatus() );
	}
	else
	{
	    TEST_ASSERT( communicator.receiveStatus() );
	}
	TEST_ASSERT( !communicator.sendStatus() );

	// Receive empty flushed buffers.
	int zero_histories = communicator.wait( bank );
	TEST_EQUALITY( zero_histories, 0 );
	TEST_ASSERT( !communicator.receiveStatus() );
	TEST_ASSERT( bank.empty() );

	// Repost receives.
	communicator.post();
	if ( comm_rank == 0 )
	{
	    TEST_ASSERT( !communicator.receiveStatus() );
	}
	else
	{
	    TEST_ASSERT( communicator.receiveStatus() );
	}

	// Proc 0 will send to proc 1.
	if ( comm_rank == 0 )
	{
	    TEST_ASSERT( !domain->isGlobalState(10) );

	    Teuchos::RCP<HistoryType> h1 =
		makeHistory( 10, 1.1, comm_rank*4 + 1 );
	    const typename MCLS::DomainCommunicator<DomainType>::Result
		r1 = communicator.communicate( h1 );
	    TEST_ASSERT( !r1.sent );
	    TEST_EQUALITY( communicator.sendBufferSize(), 1 );

	    Teuchos::RCP<HistoryType> h2 =
		makeHistory( 10, 2.1, comm_rank*4 + 2 );
	    const typename MCLS::DomainCommunicator<DomainType>::Result
		r2 = communicator.communicate( h2 );
	    TEST_ASSERT( !r2.sent );
	    TEST_EQUALITY( communicator.sendBufferSize(), 2 );

	    Teuchos::RCP<HistoryType> h3 =
		makeHistory( 10, 3.1, comm_rank*4 + 3 );
	    const typename MCLS::DomainCommunicator<DomainType>::Result
		r3 = communicator.communicate( h3 );
	    TEST_ASSERT( r3.sent );
	    TEST_EQUALITY( r3.destination, 1 );
	    TEST_EQUALITY( communicator.sendBufferSize(), 0 );
	}

	// Proc comm_rank send to proc comm_rank+1 and receive from proc
	// comm_rank-1.
	else if ( comm_rank < comm_size - 1 )
	{
	    // Send to proc comm_rank+1.
	    TEST_ASSERT( !domain->isGlobalState((comm_rank+1)*10) );

	    Teuchos::RCP<HistoryType> h1 =
		makeHistory( (comm_rank+1)*10, 1.1, comm_rank*4 + 1 );
	    const typename MCLS::DomainCommunicator<DomainType>::Result
		r1 = communicator.communicate( h1 );
	    TEST_ASSERT( !r1.sent );
	    TEST_EQUALITY( communicator.sendBufferSize(), 1 );

	    Teuchos::RCP<HistoryType> h2 =
		makeHistory( (comm_rank+1)*10, 2.1, comm_rank*4 + 2 );
	    const typename MCLS::DomainCommunicator<DomainType>::Result
		r2 = communicator.communicate( h2 );
	    TEST_ASSERT( !r2.sent );
	    TEST_EQUALITY( communicator.sendBufferSize(), 2 );

	    Teuchos::RCP<HistoryType> h3 =
		makeHistory( (comm_rank+1)*10, 3.1, comm_rank*4 + 3 );
	    const typename MCLS::DomainCommunicator<DomainType>::Result
		r3 = communicator.communicate( h3 );
	    TEST_ASSERT( r3.sent );
	    TEST_EQUALITY( r3.destination, comm_rank+1 );
	    TEST_EQUALITY( communicator.sendBufferSize(), 0 );

	    // Receive from proc comm_rank-1.
	    while ( bank.empty() )
	    {
		communicator.checkAndPost( bank );
	    }

	    TEST_EQUALITY( bank.size(), 3 );

	    Teuchos::RCP<HistoryType> rp3 = bank.top();
	    bank.pop();
	    Teuchos::RCP<HistoryType> rp2 = bank.top();
	    bank.pop();
	    Teuchos::RCP<HistoryType> rp1 = bank.top();
	    bank.pop();
	    TEST_ASSERT( bank.empty() );

	    TEST_EQUALITY( rp3->globalState(), comm_rank*10 );
	    TEST_EQUALITY( rp3->weight(), 3.1 );
	    TEST_EQUALITY( rp2->globalState(), comm_rank*10 );
	    TEST_EQUALITY( rp2->weight(), 2.1 );
	    TEST_EQUALITY( rp1->globalState(), comm_rank*10 );
	    TEST_EQUALITY( rp1->weight(), 1.1 );

	    TEST_ASSERT( communicator.receiveStatus() );
	}

	// The last proc just receives.
	else
	{
	    // Check and post until receive from proc comm_rank-1
	    while ( bank.empty() )
	    {
		communicator.checkAndPost( bank );
	    }
	    TEST_ASSERT( communicator.receiveStatus() );
	    TEST_EQUALITY( bank.size(), 3 );

	    Teuchos::RCP<HistoryType> rp3 = bank.top();
	    bank.pop();
	    Teuchos::RCP<HistoryType> rp2 = bank.top();
	    bank.pop();
	    Teuchos::RCP<HistoryType> rp1 = bank.top();
	    bank.pop();
	    TEST_ASSERT( bank.empty() );

	    TEST_EQUALITY( rp3->globalState(), comm_rank*10 );
	    TEST_EQUALITY( rp3->weight(), 3.1 );
	    TEST_EQUALITY( rp2->globalState(), comm_rank*10 );
	    TEST_EQUALITY( rp2->weight(), 2.1 );
	    TEST_EQUALITY( rp1->globalState(), comm_rank*10 );
	    TEST_EQUALITY( rp1->weight(), 1.1 );
	}

	// End communication.
	communicator.end();
	TEST_ASSERT( !communicator.receiveStatus() );
    }

    // Barrier before exiting to make sure memory deallocation happened
    // correctly.
    comm->barrier();
}

//---------------------------------------------------------------------------//
// end tstTpetraDomainCommunicator.cpp
//---------------------------------------------------------------------------//

<|endoftext|>


<commit_before>/*
   For more information, please see: http://software.sci.utah.edu

   The MIT License

   Copyright (c) 2009 Scientific Computing and Imaging Institute,
   University of Utah.

   Permission is hereby granted, free of charge, to any person obtaining a
   copy of this software and associated documentation files (the "Software"),
   to deal in the Software without restriction, including without limitation
   the rights to use, copy, modify, merge, publish, distribute, sublicense,
   and/or sell copies of the Software, and to permit persons to whom the
   Software is furnished to do so, subject to the following conditions:

   The above copyright notice and this permission notice shall be included
   in all copies or substantial portions of the Software.

   THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
   OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
   FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
   THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
   LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
   FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
   DEALINGS IN THE SOFTWARE.
*/

#include <Core/Algorithms/Legacy/Fields/RefineMesh/RefineMesh.h>
#include <Core/Datatypes/Legacy/Field/VMesh.h>
#include <Core/Datatypes/Legacy/Field/VField.h>
// For mapping matrices
#include <Core/Datatypes/Legacy/Field/FieldInformation.h>
#include <Core/Algorithms/Base/AlgorithmPreconditions.h>
#include <Core/Algorithms/Base/AlgorithmVariableNames.h>
#include <Core/Algorithms/Legacy/Fields/RefineMesh/RefineMeshTriSurfAlgoV.h>
#include <Core/Algorithms/Legacy/Fields/RefineMesh/RefineMeshTetVolAlgoV.h>
#include <Core/Algorithms/Legacy/Fields/RefineMesh/RefineMeshHexVolAlgoV.h>
#include <Core/Algorithms/Legacy/Fields/RefineMesh/RefineMeshCurveAlgoV.h>
#include <Core/Algorithms/Legacy/Fields/RefineMesh/RefineMeshQuadSurfAlgoV.h>

//STL classes needed
#include <algorithm>
#include <set>

using namespace SCIRun;
using namespace SCIRun::Core::Algorithms;
using namespace SCIRun::Core::Algorithms::Fields;
using namespace SCIRun::Core::Datatypes;
using namespace SCIRun::Core::Geometry;
using namespace SCIRun::Core::Logging;

ALGORITHM_PARAMETER_DEF(Fields, AddConstraints);
ALGORITHM_PARAMETER_DEF(Fields, RefineMethod);
ALGORITHM_PARAMETER_DEF(Fields, IsoValue);

RefineMeshAlgo::RefineMeshAlgo()
{
		using namespace Parameters;
		add_option(AddConstraints,"all","all|greaterthan|unequal|lessthan|none");
		add_option(RefineMethod,"Default","Default|Expand refinement volume to improve element quality");
		addParameter(IsoValue,0.0);
}

AlgorithmOutput RefineMeshAlgo::run_generic(const AlgorithmInput& input) const
{
	auto field = input.get<Field>(Variables::InputField);
  FieldHandle outputField;

  if (!runImpl(field, outputField))
    THROW_ALGORITHM_PROCESSING_ERROR("False returned on legacy run call.");
	AlgorithmOutput output;
	output[Variables::OutputField] = outputField;
  return output;
}

// General access function

bool
RefineMeshAlgo::runImpl(FieldHandle input, FieldHandle& output) const
{
	ScopedAlgorithmStatusReporter asr(this, "RefineMesh");
  if (!input)
  {
    error("No input field");
    return (false);
  }
	FieldInformation fi(input);
	FieldInformation fo(output);

	const std::string rMethod = get_option(Parameters::RefineMethod);
	const double isoVal = get(Parameters::IsoValue).toDouble();
	const std::string addCon = get_option(Parameters::AddConstraints);

  if (input->vfield()->num_values() == 0)
  {
    error("Input field has no data values. The RefineMesh algorithm requires input fields to contain data.");
    return (false);
  }

  if (addCon == "none")
  {
    output = input;
    return (true);
  }

  if (fi.is_pnt_element() || fi.is_prism_element())
  {
    error("This algorithm does not support point or prism meshes");
    return(false);
  }

  if ((!(fi.is_scalar()))&&(addCon != "all"))
  {
    error("Field data needs to be of scalar type");
    return (false);
  }

  if (fi.is_quad_element())
  {
    RefineMeshQuadSurfAlgoV algo;
    return(algo.runImpl(input,output,addCon,isoVal));
  }

  if (fi.is_hex_element())
  {
		bool convex = false;
		convex = rMethod == "Expand refinement volume to improve element quality";
    RefineMeshHexVolAlgoV algo;
		return(algo.runImpl(input,output,convex,addCon,isoVal));
  }

  if (fi.is_crv_element())
  {
			RefineMeshCurveAlgoV algo;
			return(algo.runImpl(input,output,addCon,isoVal));
  }

  if (fi.is_tri_element())
  {
			RefineMeshTriSurfAlgoV algo;
			return(algo.runImpl(input,output,addCon,isoVal));
  }

  if (fi.is_tet_element())
  {
			RefineMeshTetVolAlgoV algo;
			return(algo.runImpl(input,output,addCon,isoVal));
  }

  error("No refinement method has been implemented for this type of mesh");
  return (false);
}
     <commit_msg>Fix algo updater<commit_after>/*
   For more information, please see: http://software.sci.utah.edu

   The MIT License

   Copyright (c) 2009 Scientific Computing and Imaging Institute,
   University of Utah.

   Permission is hereby granted, free of charge, to any person obtaining a
   copy of this software and associated documentation files (the "Software"),
   to deal in the Software without restriction, including without limitation
   the rights to use, copy, modify, merge, publish, distribute, sublicense,
   and/or sell copies of the Software, and to permit persons to whom the
   Software is furnished to do so, subject to the following conditions:

   The above copyright notice and this permission notice shall be included
   in all copies or substantial portions of the Software.

   THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
   OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
   FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
   THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
   LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
   FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
   DEALINGS IN THE SOFTWARE.
*/

#include <Core/Algorithms/Legacy/Fields/RefineMesh/RefineMesh.h>
#include <Core/Datatypes/Legacy/Field/VMesh.h>
#include <Core/Datatypes/Legacy/Field/VField.h>
// For mapping matrices
#include <Core/Datatypes/Legacy/Field/FieldInformation.h>
#include <Core/Algorithms/Base/AlgorithmPreconditions.h>
#include <Core/Algorithms/Base/AlgorithmVariableNames.h>
#include <Core/Algorithms/Legacy/Fields/RefineMesh/RefineMeshTriSurfAlgoV.h>
#include <Core/Algorithms/Legacy/Fields/RefineMesh/RefineMeshTetVolAlgoV.h>
#include <Core/Algorithms/Legacy/Fields/RefineMesh/RefineMeshHexVolAlgoV.h>
#include <Core/Algorithms/Legacy/Fields/RefineMesh/RefineMeshCurveAlgoV.h>
#include <Core/Algorithms/Legacy/Fields/RefineMesh/RefineMeshQuadSurfAlgoV.h>

//STL classes needed
#include <algorithm>
#include <set>

using namespace SCIRun;
using namespace SCIRun::Core::Algorithms;
using namespace SCIRun::Core::Algorithms::Fields;
using namespace SCIRun::Core::Datatypes;
using namespace SCIRun::Core::Geometry;
using namespace SCIRun::Core::Logging;

ALGORITHM_PARAMETER_DEF(Fields, AddConstraints);
ALGORITHM_PARAMETER_DEF(Fields, RefineMethod);
ALGORITHM_PARAMETER_DEF(Fields, IsoValue);

RefineMeshAlgo::RefineMeshAlgo()
{
		using namespace Parameters;
		add_option(AddConstraints,"all","all|greaterthan|unequal|lessthan|none");
		add_option(RefineMethod,"Default","Default|Expand refinement volume to improve element quality");
		addParameter(IsoValue,0.0);
}

AlgorithmOutput RefineMeshAlgo::run_generic(const AlgorithmInput& input) const
{
	auto field = input.get<Field>(Variables::InputField);
  FieldHandle outputField;

  if (!runImpl(field, outputField))
    THROW_ALGORITHM_PROCESSING_ERROR("False returned on legacy run call.");
	AlgorithmOutput output;
	output[Variables::OutputField] = outputField;
  return output;
}

// General access function

bool
RefineMeshAlgo::runImpl(FieldHandle input, FieldHandle& output) const
{
	ScopedAlgorithmStatusReporter asr(this, "RefineMesh");
  if (!input)
  {
    error("No input field");
    return (false);
  }
	FieldInformation fi(input);
	FieldInformation fo(output);

	const std::string rMethod = get_option(Parameters::RefineMethod);
	const double isoVal = get(Parameters::IsoValue).toDouble();
	const std::string addCon = get_option(Parameters::AddConstraints);

  if (input->vfield()->num_values() == 0)
  {
    error("Input field has no data values. The RefineMesh algorithm requires input fields to contain data.");
    return (false);
  }

  if (addCon == "none")
  {
    output = input;
    return (true);
  }

  if (fi.is_pnt_element() || fi.is_prism_element())
  {
    error("This algorithm does not support point or prism meshes");
    return(false);
  }

  if ((!(fi.is_scalar()))&&(addCon != "all"))
  {
    error("Field data needs to be of scalar type");
    return (false);
  }

  if (fi.is_quad_element())
  {
    RefineMeshQuadSurfAlgoV algo;
    algo.setUpdaterFunc(getUpdaterFunc());
    return(algo.runImpl(input,output,addCon,isoVal));
  }

  if (fi.is_hex_element())
  {
		bool convex = false;
		convex = rMethod == "Expand refinement volume to improve element quality";
    RefineMeshHexVolAlgoV algo;
    algo.setUpdaterFunc(getUpdaterFunc());
		return(algo.runImpl(input,output,convex,addCon,isoVal));
  }

  if (fi.is_crv_element())
  {
			RefineMeshCurveAlgoV algo;
      algo.setUpdaterFunc(getUpdaterFunc());
			return(algo.runImpl(input,output,addCon,isoVal));
  }

  if (fi.is_tri_element())
  {
			RefineMeshTriSurfAlgoV algo;
      algo.setUpdaterFunc(getUpdaterFunc());
			return(algo.runImpl(input,output,addCon,isoVal));
  }

  if (fi.is_tet_element())
  {
			RefineMeshTetVolAlgoV algo;
      algo.setUpdaterFunc(getUpdaterFunc());
			return(algo.runImpl(input,output,addCon,isoVal));
  }

  error("No refinement method has been implemented for this type of mesh");
  return (false);
}
     <|endoftext|>


<commit_before>/*=========================================================================

Program:   Medical Imaging & Interaction Toolkit
Module:    $RCSfile$
Language:  C++
Date:      $Date$
Version:   $Revision$

Copyright (c) German Cancer Research Center, Division of Medical and
Biological Informatics. All rights reserved.
See MITKCopyright.txt or http://www.mitk.org/copyright.html for details.

This software is distributed WITHOUT ANY WARRANTY; without even
the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
PURPOSE.  See the above copyright notices for more information.

=========================================================================*/

#include <mitkImage.h>
#include <mitkDataTree.h>
#include <mitkRenderWindow.h>
#include <mitkImageMapper2D.h>
#include <mitkLevelWindow.h>
#include <mitkLevelWindowProperty.h>

#include <mitkNativeRenderWindowInteractor.h>

#include "itkTextOutput.h"

#include <fstream>
int mitkDataTreeTest(int argc, char* argv[])
{
  itk::OutputWindow::SetInstance(
       itk::TextOutput::New().GetPointer() );

  //Create Image out of nowhere
	mitk::Image::Pointer image;
	mitk::PixelType pt(typeid(int));
	unsigned int dim[]={100,100,20};

  std::cout << "Creating image: ";
	image=mitk::Image::New();
  image->DebugOn();
	image->Initialize(mitk::PixelType(typeid(int)), 3, dim);
  int *p = (int*)image->GetData();

  int size = dim[0]*dim[1]*dim[2];
  int i;
  for(i=0; i<size; ++i, ++p)
    *p=i;
  std::cout<<"[PASSED]"<<std::endl;

  {
    std::cout << "Creating node: ";
    mitk::DataTreeNode::Pointer node = mitk::DataTreeNode::New();
    node->SetData(image);
    std::cout<<"[PASSED]"<<std::endl;
  }

  std::cout << "Creating node: ";
  mitk::DataTreeNode::Pointer node = mitk::DataTreeNode::New();
  node->SetData(image);
  std::cout<<"[PASSED]"<<std::endl;

  std::cout << "Creating tree: ";
  mitk::DataTree::Pointer tree;
  tree=mitk::DataTree::New(); //@FIXME: da DataTreeIteratorClone keinen Smartpointer auf DataTree hlt, wird tree sonst gelscht.
  std::cout<<"[PASSED]"<<std::endl;

  std::cout << "Creating iterator on tree: ";
  mitk::DataTreePreOrderIterator it(tree);
  std::cout<<"[PASSED]"<<std::endl;

  std::cout << "Adding node via iterator: ";
  it.Add(node);
  std::cout<<"[PASSED]"<<std::endl;

  std::cout << "Adding level-window property: ";
  mitk::LevelWindowProperty::Pointer levWinProp = new mitk::LevelWindowProperty();
  mitk::LevelWindow levelwindow;
  levelwindow.SetAuto( image );
  levWinProp->SetLevelWindow( levelwindow );
  node->GetPropertyList()->SetProperty( "levelwindow", levWinProp );
  std::cout<<"[PASSED]"<<std::endl;

  std::cout << "Remove node after incrementing iterator: ";
  it++;
  if (it.Remove()) std::cout<<"[PASSED]"<<std::endl;
  else std::cout<<"[FAILED]"<<std::endl;

  std::cout<<"[TEST DONE]"<<std::endl;
  return EXIT_SUCCESS;
}
<commit_msg>FIX: linux compatibility: ++ must be prefix for tree-iterators<commit_after>/*=========================================================================

Program:   Medical Imaging & Interaction Toolkit
Module:    $RCSfile$
Language:  C++
Date:      $Date$
Version:   $Revision$

Copyright (c) German Cancer Research Center, Division of Medical and
Biological Informatics. All rights reserved.
See MITKCopyright.txt or http://www.mitk.org/copyright.html for details.

This software is distributed WITHOUT ANY WARRANTY; without even
the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
PURPOSE.  See the above copyright notices for more information.

=========================================================================*/

#include <mitkImage.h>
#include <mitkDataTree.h>
#include <mitkRenderWindow.h>
#include <mitkImageMapper2D.h>
#include <mitkLevelWindow.h>
#include <mitkLevelWindowProperty.h>

#include <mitkNativeRenderWindowInteractor.h>

#include "itkTextOutput.h"

#include <fstream>
int mitkDataTreeTest(int argc, char* argv[])
{
  itk::OutputWindow::SetInstance(
       itk::TextOutput::New().GetPointer() );

  //Create Image out of nowhere
	mitk::Image::Pointer image;
	mitk::PixelType pt(typeid(int));
	unsigned int dim[]={100,100,20};

  std::cout << "Creating image: ";
	image=mitk::Image::New();
  image->DebugOn();
	image->Initialize(mitk::PixelType(typeid(int)), 3, dim);
  int *p = (int*)image->GetData();

  int size = dim[0]*dim[1]*dim[2];
  int i;
  for(i=0; i<size; ++i, ++p)
    *p=i;
  std::cout<<"[PASSED]"<<std::endl;

  {
    std::cout << "Creating node: ";
    mitk::DataTreeNode::Pointer node = mitk::DataTreeNode::New();
    node->SetData(image);
    std::cout<<"[PASSED]"<<std::endl;
  }

  std::cout << "Creating node: ";
  mitk::DataTreeNode::Pointer node = mitk::DataTreeNode::New();
  node->SetData(image);
  std::cout<<"[PASSED]"<<std::endl;

  std::cout << "Creating tree: ";
  mitk::DataTree::Pointer tree;
  tree=mitk::DataTree::New(); //@FIXME: da DataTreeIteratorClone keinen Smartpointer auf DataTree hlt, wird tree sonst gelscht.
  std::cout<<"[PASSED]"<<std::endl;

  std::cout << "Creating iterator on tree: ";
  mitk::DataTreePreOrderIterator it(tree);
  std::cout<<"[PASSED]"<<std::endl;

  std::cout << "Adding node via iterator: ";
  it.Add(node);
  std::cout<<"[PASSED]"<<std::endl;

  std::cout << "Adding level-window property: ";
  mitk::LevelWindowProperty::Pointer levWinProp = new mitk::LevelWindowProperty();
  mitk::LevelWindow levelwindow;
  levelwindow.SetAuto( image );
  levWinProp->SetLevelWindow( levelwindow );
  node->GetPropertyList()->SetProperty( "levelwindow", levWinProp );
  std::cout<<"[PASSED]"<<std::endl;

  std::cout << "Remove node after incrementing iterator: ";
  ++it;
  if (it.Remove()) std::cout<<"[PASSED]"<<std::endl;
  else std::cout<<"[FAILED]"<<std::endl;

  std::cout<<"[TEST DONE]"<<std::endl;
  return EXIT_SUCCESS;
}
<|endoftext|>