<commit_before>#include <Arduino.h>
#include "DDS.h"

// To start the DDS, we use Timer1, set to the reference clock
// We use Timer2 for the PWM output, running as fast as feasible
void DDS::start() {
  // Use the clkIO clock rate
  ASSR &= ~(_BV(EXCLK) | _BV(AS2));

  // First, the timer for the PWM output
  // Setup the timer to use OC2B (pin 3) in fast PWM mode with a configurable top
  // Run it without the prescaler
#ifdef DDS_PWM_PIN_3
  TCCR2A = (TCCR2A | _BV(COM2B1)) & ~(_BV(COM2B0) | _BV(COM2A1) | _BV(COM2A0)) |
         _BV(WGM21) | _BV(WGM20);
  TCCR2B = (TCCR2B & ~(_BV(CS22) | _BV(CS21))) | _BV(CS20) | _BV(WGM22);
#else
  // Alternatively, use pin 11
  // Enable output compare on OC2A, toggle mode
  TCCR2A = _BV(COM2A1) | _BV(WGM21) | _BV(WGM20);
  //TCCR2A = (TCCR2A | _BV(COM2A1)) & ~(_BV(COM2A0) | _BV(COM2B1) | _BV(COM2B0)) |
  //     _BV(WGM21) | _BV(WGM20);
  TCCR2B = _BV(CS20);
#endif

  // Set the top limit, which will be our duty cycle accuracy.
  // Setting Comparator Bits smaller will allow for higher frequency PWM,
  // with the loss of resolution.
#ifdef DDS_PWM_PIN_3
  OCR2A = pow(2,COMPARATOR_BITS)-1;
  OCR2B = 0;
#else
  OCR2A = 0;
#endif

#ifdef DDS_USE_ONLY_TIMER2
  TIMSK2 |= _BV(TOIE2);
#endif

  // Second, setup Timer1 to trigger the ADC interrupt
  // This lets us use decoding functions that run at the same reference
  // clock as the DDS.
  // We use ICR1 as TOP and prescale by 8
  TCCR1B = _BV(CS10) | _BV(WGM13) | _BV(WGM12);
  TCCR1A = 0;
  ICR1 = ((F_CPU / 1) / refclk) - 1;
#ifdef DDS_DEBUG_SERIAL
  Serial.print(F("DDS SysClk: "));
  Serial.println(F_CPU/8);
  Serial.print(F("DDS RefClk: "));
  Serial.println(refclk, DEC);
  Serial.print(F("DDS ICR1: "));
  Serial.println(ICR1, DEC);
#endif

  // Configure the ADC here to automatically run and be triggered off Timer1
  ADMUX = _BV(REFS0) | _BV(ADLAR) | 0; // Channel 0, shift result left (ADCH used)
  DDRC &= ~_BV(0);
  PORTC &= ~_BV(0);
  DIDR0 |= _BV(0);
  ADCSRB = _BV(ADTS2) | _BV(ADTS1) | _BV(ADTS0);
  ADCSRA = _BV(ADEN) | _BV(ADSC) | _BV(ADATE) | _BV(ADIE) | _BV(ADPS2); // | _BV(ADPS0);
}

void DDS::stop() {
  // TODO: Stop the timers.
#ifndef DDS_USE_ONLY_TIMER2
  TCCR1B = 0;
#endif
  TCCR2B = 0;
}

// Set our current sine wave frequency in Hz
ddsAccumulator_t DDS::calcFrequency(unsigned short freq) {
  // Fo = (M*Fc)/2^N
  // M = (Fo/Fc)*2^N
  ddsAccumulator_t newStep;
  if(refclk == DDS_REFCLK_DEFAULT) {
    // Try to use precalculated values if possible
    if(freq == 2200) {
      newStep = (2200.0 / (DDS_REFCLK_DEFAULT+DDS_REFCLK_OFFSET)) * pow(2,ACCUMULATOR_BITS);
    } else if (freq == 1200) {
      newStep = (1200.0 / (DDS_REFCLK_DEFAULT+DDS_REFCLK_OFFSET)) * pow(2,ACCUMULATOR_BITS);
    } else if(freq == 2400) {
      newStep = (2400.0 / (DDS_REFCLK_DEFAULT+DDS_REFCLK_OFFSET)) * pow(2,ACCUMULATOR_BITS);
    } else if (freq == 1500) {
      newStep = (1500.0 / (DDS_REFCLK_DEFAULT+DDS_REFCLK_OFFSET)) * pow(2,ACCUMULATOR_BITS);
    } else if (freq == 600) {
      newStep = (600.0 / (DDS_REFCLK_DEFAULT+DDS_REFCLK_OFFSET)) * pow(2,ACCUMULATOR_BITS);
    }
  } else {
    newStep = pow(2,ACCUMULATOR_BITS)*freq / (refclk+refclkOffset);
  }
  return newStep;
}

// Degrees should be between -360 and +360 (others don't make much sense)
void DDS::setPhaseDeg(int16_t degrees) {
  accumulator = degrees * (pow(2,ACCUMULATOR_BITS)/360.0);
}
void DDS::changePhaseDeg(int16_t degrees) {
  accumulator += degrees * (pow(2,ACCUMULATOR_BITS)/360.0);
}

// TODO: Clean this up a bit..
void DDS::clockTick() {
/*  if(running) {
    accumulator += stepRate;
    OCR2A = getDutyCycle();
  }
  return;*/
  if(running) {
    accumulator += stepRate;
    if(timeLimited && tickDuration == 0) {
#ifndef DDS_PWM_PIN_3
      OCR2A = 0;
#else
#ifdef DDS_IDLE_HIGH
      // Set the duty cycle to 50%
      OCR2B = pow(2,COMPARATOR_BITS)/2;
#else
      // Set duty cycle to 0, effectively off
      OCR2B = 0;
#endif
#endif
      running = false;
      accumulator = 0;
    } else {
#ifdef DDS_PWM_PIN_3
      OCR2B = getDutyCycle();
#else
      OCR2A = getDutyCycle();
#endif
    }
    // Reduce our playback duration by one tick
    tickDuration--;
  } else {
    // Hold it low
#ifndef DDS_PWM_PIN_3
    OCR2A = 0;
#else
#ifdef DDS_IDLE_HIGH
    // Set the duty cycle to 50%
    OCR2B = pow(2,COMPARATOR_BITS)/2;
#else
    // Set duty cycle to 0, effectively off
    OCR2B = 0;
#endif
#endif
  }
}

uint8_t DDS::getDutyCycle() {
  #if ACCUMULATOR_BIT_SHIFT >= 24
    uint16_t phAng;
  #else
    uint8_t phAng;
  #endif
  if(amplitude == 0) // Shortcut out on no amplitude
    return 128>>(8-COMPARATOR_BITS);
  phAng = (accumulator >> ACCUMULATOR_BIT_SHIFT);
  int8_t position = pgm_read_byte_near(ddsSineTable + phAng); //>>(8-COMPARATOR_BITS);
  // Apply scaling and return
  int16_t scaled = position;
  // output = ((duty * amplitude) / 256) + 128
  // This keeps amplitudes centered around 50% duty
  if(amplitude != 255) { // Amplitude is reduced, so do the full math
    scaled *= amplitude;
    scaled >>= 8+(8-COMPARATOR_BITS);
  } else { // Otherwise, only shift for the comparator bits
    scaled >>= (8-COMPARATOR_BITS);
  }
  scaled += 128>>(8-COMPARATOR_BITS);
  return scaled;
}
<commit_msg>Fixed DDS.cpp to reference ADC channel 2 instead of old channel 0.<commit_after>#include <Arduino.h>
#include "DDS.h"

// To start the DDS, we use Timer1, set to the reference clock
// We use Timer2 for the PWM output, running as fast as feasible
void DDS::start() {
  // Use the clkIO clock rate
  ASSR &= ~(_BV(EXCLK) | _BV(AS2));

  // First, the timer for the PWM output
  // Setup the timer to use OC2B (pin 3) in fast PWM mode with a configurable top
  // Run it without the prescaler
#ifdef DDS_PWM_PIN_3
  TCCR2A = (TCCR2A | _BV(COM2B1)) & ~(_BV(COM2B0) | _BV(COM2A1) | _BV(COM2A0)) |
         _BV(WGM21) | _BV(WGM20);
  TCCR2B = (TCCR2B & ~(_BV(CS22) | _BV(CS21))) | _BV(CS20) | _BV(WGM22);
#else
  // Alternatively, use pin 11
  // Enable output compare on OC2A, toggle mode
  TCCR2A = _BV(COM2A1) | _BV(WGM21) | _BV(WGM20);
  //TCCR2A = (TCCR2A | _BV(COM2A1)) & ~(_BV(COM2A0) | _BV(COM2B1) | _BV(COM2B0)) |
  //     _BV(WGM21) | _BV(WGM20);
  TCCR2B = _BV(CS20);
#endif

  // Set the top limit, which will be our duty cycle accuracy.
  // Setting Comparator Bits smaller will allow for higher frequency PWM,
  // with the loss of resolution.
#ifdef DDS_PWM_PIN_3
  OCR2A = pow(2,COMPARATOR_BITS)-1;
  OCR2B = 0;
#else
  OCR2A = 0;
#endif

#ifdef DDS_USE_ONLY_TIMER2
  TIMSK2 |= _BV(TOIE2);
#endif

  // Second, setup Timer1 to trigger the ADC interrupt
  // This lets us use decoding functions that run at the same reference
  // clock as the DDS.
  // We use ICR1 as TOP and prescale by 8
  TCCR1B = _BV(CS10) | _BV(WGM13) | _BV(WGM12);
  TCCR1A = 0;
  ICR1 = ((F_CPU / 1) / refclk) - 1;
#ifdef DDS_DEBUG_SERIAL
  Serial.print(F("DDS SysClk: "));
  Serial.println(F_CPU/8);
  Serial.print(F("DDS RefClk: "));
  Serial.println(refclk, DEC);
  Serial.print(F("DDS ICR1: "));
  Serial.println(ICR1, DEC);
#endif

  // Configure the ADC here to automatically run and be triggered off Timer1
  ADMUX = _BV(REFS0) | _BV(ADLAR) | 2; // Channel 2, shift result left (ADCH used)
  DDRC &= ~_BV(0);
  PORTC &= ~_BV(0);
  DIDR0 |= _BV(0);
  ADCSRB = _BV(ADTS2) | _BV(ADTS1) | _BV(ADTS0);
  ADCSRA = _BV(ADEN) | _BV(ADSC) | _BV(ADATE) | _BV(ADIE) | _BV(ADPS2); // | _BV(ADPS0);
}

void DDS::stop() {
  // TODO: Stop the timers.
#ifndef DDS_USE_ONLY_TIMER2
  TCCR1B = 0;
#endif
  TCCR2B = 0;
}

// Set our current sine wave frequency in Hz
ddsAccumulator_t DDS::calcFrequency(unsigned short freq) {
  // Fo = (M*Fc)/2^N
  // M = (Fo/Fc)*2^N
  ddsAccumulator_t newStep;
  if(refclk == DDS_REFCLK_DEFAULT) {
    // Try to use precalculated values if possible
    if(freq == 2200) {
      newStep = (2200.0 / (DDS_REFCLK_DEFAULT+DDS_REFCLK_OFFSET)) * pow(2,ACCUMULATOR_BITS);
    } else if (freq == 1200) {
      newStep = (1200.0 / (DDS_REFCLK_DEFAULT+DDS_REFCLK_OFFSET)) * pow(2,ACCUMULATOR_BITS);
    } else if(freq == 2400) {
      newStep = (2400.0 / (DDS_REFCLK_DEFAULT+DDS_REFCLK_OFFSET)) * pow(2,ACCUMULATOR_BITS);
    } else if (freq == 1500) {
      newStep = (1500.0 / (DDS_REFCLK_DEFAULT+DDS_REFCLK_OFFSET)) * pow(2,ACCUMULATOR_BITS);
    } else if (freq == 600) {
      newStep = (600.0 / (DDS_REFCLK_DEFAULT+DDS_REFCLK_OFFSET)) * pow(2,ACCUMULATOR_BITS);
    }
  } else {
    newStep = pow(2,ACCUMULATOR_BITS)*freq / (refclk+refclkOffset);
  }
  return newStep;
}

// Degrees should be between -360 and +360 (others don't make much sense)
void DDS::setPhaseDeg(int16_t degrees) {
  accumulator = degrees * (pow(2,ACCUMULATOR_BITS)/360.0);
}
void DDS::changePhaseDeg(int16_t degrees) {
  accumulator += degrees * (pow(2,ACCUMULATOR_BITS)/360.0);
}

// TODO: Clean this up a bit..
void DDS::clockTick() {
/*  if(running) {
    accumulator += stepRate;
    OCR2A = getDutyCycle();
  }
  return;*/
  if(running) {
    accumulator += stepRate;
    if(timeLimited && tickDuration == 0) {
#ifndef DDS_PWM_PIN_3
      OCR2A = 0;
#else
#ifdef DDS_IDLE_HIGH
      // Set the duty cycle to 50%
      OCR2B = pow(2,COMPARATOR_BITS)/2;
#else
      // Set duty cycle to 0, effectively off
      OCR2B = 0;
#endif
#endif
      running = false;
      accumulator = 0;
    } else {
#ifdef DDS_PWM_PIN_3
      OCR2B = getDutyCycle();
#else
      OCR2A = getDutyCycle();
#endif
    }
    // Reduce our playback duration by one tick
    tickDuration--;
  } else {
    // Hold it low
#ifndef DDS_PWM_PIN_3
    OCR2A = 0;
#else
#ifdef DDS_IDLE_HIGH
    // Set the duty cycle to 50%
    OCR2B = pow(2,COMPARATOR_BITS)/2;
#else
    // Set duty cycle to 0, effectively off
    OCR2B = 0;
#endif
#endif
  }
}

uint8_t DDS::getDutyCycle() {
  #if ACCUMULATOR_BIT_SHIFT >= 24
    uint16_t phAng;
  #else
    uint8_t phAng;
  #endif
  if(amplitude == 0) // Shortcut out on no amplitude
    return 128>>(8-COMPARATOR_BITS);
  phAng = (accumulator >> ACCUMULATOR_BIT_SHIFT);
  int8_t position = pgm_read_byte_near(ddsSineTable + phAng); //>>(8-COMPARATOR_BITS);
  // Apply scaling and return
  int16_t scaled = position;
  // output = ((duty * amplitude) / 256) + 128
  // This keeps amplitudes centered around 50% duty
  if(amplitude != 255) { // Amplitude is reduced, so do the full math
    scaled *= amplitude;
    scaled >>= 8+(8-COMPARATOR_BITS);
  } else { // Otherwise, only shift for the comparator bits
    scaled >>= (8-COMPARATOR_BITS);
  }
  scaled += 128>>(8-COMPARATOR_BITS);
  return scaled;
}
<|endoftext|>


<commit_before>// Copyright (c) 2021 The Orbit Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include <absl/container/flat_hash_map.h>
#include <absl/strings/substitute.h>
#include <absl/synchronization/mutex.h>
#include <absl/time/clock.h>
#include <gmock/gmock.h>
#include <gtest/gtest.h>

#include <numeric>

#include "GrpcProtos/Constants.h"
#include "MemoryTracing/MemoryInfoListener.h"
#include "MemoryTracing/MemoryInfoProducer.h"
#include "MemoryTracingUtils.h"
#include "OrbitBase/Logging.h"
#include "OrbitBase/Profiling.h"
#include "OrbitBase/ThreadUtils.h"
#include "capture.pb.h"

namespace orbit_memory_tracing {
namespace {

using orbit_grpc_protos::CGroupMemoryUsage;
using orbit_grpc_protos::kMissingInfo;
using orbit_grpc_protos::MemoryUsageEvent;
using orbit_grpc_protos::ProcessMemoryUsage;
using orbit_grpc_protos::ProducerCaptureEvent;
using orbit_grpc_protos::SystemMemoryUsage;
using orbit_memory_tracing::MemoryInfoListener;
using orbit_memory_tracing::MemoryInfoProducer;

class BufferMemoryInfoListener : public MemoryInfoListener {
 public:
  [[nodiscard]] std::vector<ProducerCaptureEvent> GetAndClearEvents() {
    absl::MutexLock lock{&events_mutex_};
    std::vector<ProducerCaptureEvent> events = std::move(events_);
    events_.clear();
    return events;
  }

 private:
  void OnMemoryUsageEvent(MemoryUsageEvent memory_usage_event) override {
    ProducerCaptureEvent event;
    *event.mutable_memory_usage_event() = std::move(memory_usage_event);

    absl::MutexLock lock{&events_mutex_};
    events_.emplace_back(std::move(event));
  }

  std::vector<ProducerCaptureEvent> events_;
  absl::Mutex events_mutex_;
};

class MemoryTracingIntegrationTestFixture {
 public:
  explicit MemoryTracingIntegrationTestFixture(uint64_t memory_sampling_period_ns)
      : memory_sampling_period_ns_(memory_sampling_period_ns) {}

  void StartTracing() {
    CHECK(!listener_.has_value());
    CHECK(system_memory_info_producer_ == nullptr);
    CHECK(cgroup_memory_info_producer_ == nullptr);
    CHECK(process_memory_info_producer_ == nullptr);

    listener_.emplace();
    listener_->SetSamplingStartTimestampNs(orbit_base::CaptureTimestampNs());
    listener_->SetSamplingPeriodNs(memory_sampling_period_ns_);
    // Collect the cgroup memory information only if the process's memory cgroup and the cgroup
    // memory.stat file can be found successfully
    int32_t pid = static_cast<int32_t>(orbit_base::GetCurrentProcessId());
    listener_->SetEnableCGroupMemory(GetCGroupMemoryUsage(pid).has_value());
    listener_->SetEnableProcessMemory(true);

    system_memory_info_producer_ =
        CreateSystemMemoryInfoProducer(&*listener_, memory_sampling_period_ns_, pid);
    system_memory_info_producer_->Start();

    cgroup_memory_info_producer_ =
        CreateCGroupMemoryInfoProducer(&*listener_, memory_sampling_period_ns_, pid);
    cgroup_memory_info_producer_->Start();

    process_memory_info_producer_ =
        CreateProcessMemoryInfoProducer(&*listener_, memory_sampling_period_ns_, pid);
    process_memory_info_producer_->Start();
  }

  [[nodiscard]] std::vector<ProducerCaptureEvent> StopTracingAndGetEvents() {
    CHECK(listener_.has_value());
    CHECK(system_memory_info_producer_ != nullptr);
    CHECK(cgroup_memory_info_producer_ != nullptr);
    CHECK(process_memory_info_producer_ != nullptr);

    system_memory_info_producer_->Stop();
    system_memory_info_producer_.reset();

    cgroup_memory_info_producer_->Stop();
    cgroup_memory_info_producer_.reset();

    process_memory_info_producer_->Stop();
    process_memory_info_producer_.reset();

    std::vector<ProducerCaptureEvent> events = listener_->GetAndClearEvents();
    listener_.reset();
    return events;
  }

 private:
  uint64_t memory_sampling_period_ns_;
  std::unique_ptr<MemoryInfoProducer> cgroup_memory_info_producer_;
  std::unique_ptr<MemoryInfoProducer> process_memory_info_producer_;
  std::unique_ptr<MemoryInfoProducer> system_memory_info_producer_;
  std::optional<BufferMemoryInfoListener> listener_ = std::nullopt;
};

[[nodiscard]] std::vector<ProducerCaptureEvent> TraceAndGetEvents(
    MemoryTracingIntegrationTestFixture* fixture, absl::Duration tracing_period) {
  CHECK(fixture != nullptr);

  fixture->StartTracing();
  absl::SleepFor(tracing_period);
  return fixture->StopTracingAndGetEvents();
}

void VerifyOrderAndContentOfEvents(const std::vector<ProducerCaptureEvent>& events,
                                   uint64_t sampling_period_ns) {
  const uint64_t kMemoryEventsTimeDifferenceTolerace =
      static_cast<uint64_t>(sampling_period_ns * 0.1);
  uint64_t previous_memory_usage_event_timestamp_ns = 0;

  for (const auto& event : events) {
    EXPECT_TRUE(event.event_case() == ProducerCaptureEvent::kMemoryUsageEvent);
    const MemoryUsageEvent& memory_usage_event = event.memory_usage_event();

    // Verify whether events are in order of their timestamps.
    uint64_t current_memory_usage_event_timestamp_ns = memory_usage_event.timestamp_ns();
    EXPECT_GE(current_memory_usage_event_timestamp_ns, previous_memory_usage_event_timestamp_ns);

    std::vector<uint64_t> timestamps;
    // Verify whether the contents of system memory events are valid.
    EXPECT_TRUE(memory_usage_event.has_system_memory_usage());
    const SystemMemoryUsage& system_memory_usage = memory_usage_event.system_memory_usage();
    timestamps.push_back(system_memory_usage.timestamp_ns());
    EXPECT_GE(system_memory_usage.total_kb(), 0);
    EXPECT_GE(system_memory_usage.free_kb(), 0);
    EXPECT_GE(system_memory_usage.available_kb(), 0);
    EXPECT_GE(system_memory_usage.buffers_kb(), 0);
    EXPECT_GE(system_memory_usage.cached_kb(), 0);
    EXPECT_GE(system_memory_usage.pgfault(), 0);
    EXPECT_GE(system_memory_usage.pgmajfault(), 0);

    // Verify whether the contents of process memory events are valid.
    EXPECT_TRUE(memory_usage_event.has_process_memory_usage());
    const ProcessMemoryUsage& process_memory_usage = memory_usage_event.process_memory_usage();
    timestamps.push_back(process_memory_usage.timestamp_ns());
    EXPECT_GE(process_memory_usage.rss_anon_kb(), 0);
    EXPECT_GE(process_memory_usage.minflt(), 0);
    EXPECT_GE(process_memory_usage.majflt(), 0);

    // If cgroup memory events are collected, verify whether the contents are valid.
    if (memory_usage_event.has_cgroup_memory_usage()) {
      const CGroupMemoryUsage& cgroup_memory_usage = memory_usage_event.cgroup_memory_usage();
      EXPECT_FALSE(cgroup_memory_usage.cgroup_name().empty());
      timestamps.push_back(cgroup_memory_usage.timestamp_ns());
      EXPECT_GE(cgroup_memory_usage.limit_bytes(), 0);
      EXPECT_GE(cgroup_memory_usage.rss_bytes(), 0);
      EXPECT_GE(cgroup_memory_usage.mapped_file_bytes(), 0);
      EXPECT_GE(cgroup_memory_usage.pgfault(), 0);
      EXPECT_GE(cgroup_memory_usage.pgmajfault(), 0);
      EXPECT_GE(cgroup_memory_usage.unevictable_bytes(), 0);
      EXPECT_GE(cgroup_memory_usage.inactive_anon_bytes(), 0);
      EXPECT_GE(cgroup_memory_usage.active_anon_bytes(), 0);
      EXPECT_GE(cgroup_memory_usage.inactive_file_bytes(), 0);
      EXPECT_GE(cgroup_memory_usage.active_file_bytes(), 0);
    }

    // Verify that the memory events in the same memory_usage_event are sampled at very close time.
    uint64_t max_timestamp = *std::max_element(timestamps.begin(), timestamps.end());
    uint64_t min_timestamp = *std::min_element(timestamps.begin(), timestamps.end());
    EXPECT_LE(max_timestamp - min_timestamp, kMemoryEventsTimeDifferenceTolerace);
  }
}

// Verify whether the memory_sampling_period_ns_ works as expected by checking the number of
// received events.
void VerifyEventCounts(const std::vector<ProducerCaptureEvent>& events, size_t expected_counts) {
  constexpr size_t kEventCountsErrorTolerance = 2;

  size_t num_received_events = 0;
  for (const auto& event : events) {
    if (event.event_case() == ProducerCaptureEvent::kMemoryUsageEvent) num_received_events++;
  }

  EXPECT_GE(num_received_events, expected_counts - kEventCountsErrorTolerance);
}

}  // namespace

TEST(MemoryTracingIntegrationTest, MemoryTracing) {
  const uint64_t kMemorySamplingPeriodNs = absl::Milliseconds(100) / absl::Nanoseconds(1);
  const size_t kPeriodCounts = 10;

  MemoryTracingIntegrationTestFixture fixture(kMemorySamplingPeriodNs);

  absl::Duration tracing_period = absl::Nanoseconds(kMemorySamplingPeriodNs * kPeriodCounts);
  std::vector<ProducerCaptureEvent> events = TraceAndGetEvents(&fixture, tracing_period);

  VerifyOrderAndContentOfEvents(events, kMemorySamplingPeriodNs);

  VerifyEventCounts(events, kPeriodCounts);
}

}  // namespace orbit_memory_tracing<commit_msg>Fix flaky memory integration test<commit_after>// Copyright (c) 2021 The Orbit Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include <absl/container/flat_hash_map.h>
#include <absl/strings/substitute.h>
#include <absl/synchronization/mutex.h>
#include <absl/time/clock.h>
#include <gmock/gmock.h>
#include <gtest/gtest.h>

#include <numeric>

#include "GrpcProtos/Constants.h"
#include "MemoryTracing/MemoryInfoListener.h"
#include "MemoryTracing/MemoryInfoProducer.h"
#include "MemoryTracingUtils.h"
#include "OrbitBase/Logging.h"
#include "OrbitBase/Profiling.h"
#include "OrbitBase/ThreadUtils.h"
#include "capture.pb.h"

namespace orbit_memory_tracing {
namespace {

using orbit_grpc_protos::CGroupMemoryUsage;
using orbit_grpc_protos::kMissingInfo;
using orbit_grpc_protos::MemoryUsageEvent;
using orbit_grpc_protos::ProcessMemoryUsage;
using orbit_grpc_protos::ProducerCaptureEvent;
using orbit_grpc_protos::SystemMemoryUsage;
using orbit_memory_tracing::MemoryInfoListener;
using orbit_memory_tracing::MemoryInfoProducer;

class BufferMemoryInfoListener : public MemoryInfoListener {
 public:
  [[nodiscard]] std::vector<ProducerCaptureEvent> GetAndClearEvents() {
    absl::MutexLock lock{&events_mutex_};
    std::vector<ProducerCaptureEvent> events = std::move(events_);
    events_.clear();
    return events;
  }

 private:
  void OnMemoryUsageEvent(MemoryUsageEvent memory_usage_event) override {
    ProducerCaptureEvent event;
    *event.mutable_memory_usage_event() = std::move(memory_usage_event);

    absl::MutexLock lock{&events_mutex_};
    events_.emplace_back(std::move(event));
  }

  std::vector<ProducerCaptureEvent> events_;
  absl::Mutex events_mutex_;
};

class MemoryTracingIntegrationTestFixture {
 public:
  explicit MemoryTracingIntegrationTestFixture(uint64_t memory_sampling_period_ns)
      : memory_sampling_period_ns_(memory_sampling_period_ns) {}

  void StartTracing() {
    CHECK(!listener_.has_value());
    CHECK(system_memory_info_producer_ == nullptr);
    CHECK(cgroup_memory_info_producer_ == nullptr);
    CHECK(process_memory_info_producer_ == nullptr);

    listener_.emplace();
    listener_->SetSamplingStartTimestampNs(orbit_base::CaptureTimestampNs());
    listener_->SetSamplingPeriodNs(memory_sampling_period_ns_);
    // Collect the cgroup memory information only if the process's memory cgroup and the cgroup
    // memory.stat file can be found successfully
    int32_t pid = static_cast<int32_t>(orbit_base::GetCurrentProcessId());
    listener_->SetEnableCGroupMemory(GetCGroupMemoryUsage(pid).has_value());
    listener_->SetEnableProcessMemory(true);

    system_memory_info_producer_ =
        CreateSystemMemoryInfoProducer(&*listener_, memory_sampling_period_ns_, pid);
    system_memory_info_producer_->Start();

    cgroup_memory_info_producer_ =
        CreateCGroupMemoryInfoProducer(&*listener_, memory_sampling_period_ns_, pid);
    cgroup_memory_info_producer_->Start();

    process_memory_info_producer_ =
        CreateProcessMemoryInfoProducer(&*listener_, memory_sampling_period_ns_, pid);
    process_memory_info_producer_->Start();
  }

  [[nodiscard]] std::vector<ProducerCaptureEvent> StopTracingAndGetEvents() {
    CHECK(listener_.has_value());
    CHECK(system_memory_info_producer_ != nullptr);
    CHECK(cgroup_memory_info_producer_ != nullptr);
    CHECK(process_memory_info_producer_ != nullptr);

    system_memory_info_producer_->Stop();
    system_memory_info_producer_.reset();

    cgroup_memory_info_producer_->Stop();
    cgroup_memory_info_producer_.reset();

    process_memory_info_producer_->Stop();
    process_memory_info_producer_.reset();

    std::vector<ProducerCaptureEvent> events = listener_->GetAndClearEvents();
    listener_.reset();
    return events;
  }

 private:
  uint64_t memory_sampling_period_ns_;
  std::unique_ptr<MemoryInfoProducer> cgroup_memory_info_producer_;
  std::unique_ptr<MemoryInfoProducer> process_memory_info_producer_;
  std::unique_ptr<MemoryInfoProducer> system_memory_info_producer_;
  std::optional<BufferMemoryInfoListener> listener_ = std::nullopt;
};

[[nodiscard]] std::vector<ProducerCaptureEvent> TraceAndGetEvents(
    MemoryTracingIntegrationTestFixture* fixture, absl::Duration tracing_period) {
  CHECK(fixture != nullptr);

  fixture->StartTracing();
  absl::SleepFor(tracing_period);
  return fixture->StopTracingAndGetEvents();
}

void VerifyOrderAndContentOfEvents(const std::vector<ProducerCaptureEvent>& events,
                                   uint64_t sampling_period_ns) {
  const uint64_t kMemoryEventsTimeDifferenceTolerace =
      static_cast<uint64_t>(sampling_period_ns * 0.2);
  uint64_t previous_memory_usage_event_timestamp_ns = 0;

  for (const auto& event : events) {
    EXPECT_TRUE(event.event_case() == ProducerCaptureEvent::kMemoryUsageEvent);
    const MemoryUsageEvent& memory_usage_event = event.memory_usage_event();

    // Verify whether events are in order of their timestamps.
    uint64_t current_memory_usage_event_timestamp_ns = memory_usage_event.timestamp_ns();
    EXPECT_GE(current_memory_usage_event_timestamp_ns, previous_memory_usage_event_timestamp_ns);

    std::vector<uint64_t> timestamps;
    // Verify whether the contents of system memory events are valid.
    EXPECT_TRUE(memory_usage_event.has_system_memory_usage());
    const SystemMemoryUsage& system_memory_usage = memory_usage_event.system_memory_usage();
    timestamps.push_back(system_memory_usage.timestamp_ns());
    EXPECT_GE(system_memory_usage.total_kb(), 0);
    EXPECT_GE(system_memory_usage.free_kb(), 0);
    EXPECT_GE(system_memory_usage.available_kb(), 0);
    EXPECT_GE(system_memory_usage.buffers_kb(), 0);
    EXPECT_GE(system_memory_usage.cached_kb(), 0);
    EXPECT_GE(system_memory_usage.pgfault(), 0);
    EXPECT_GE(system_memory_usage.pgmajfault(), 0);

    // Verify whether the contents of process memory events are valid.
    EXPECT_TRUE(memory_usage_event.has_process_memory_usage());
    const ProcessMemoryUsage& process_memory_usage = memory_usage_event.process_memory_usage();
    timestamps.push_back(process_memory_usage.timestamp_ns());
    EXPECT_GE(process_memory_usage.rss_anon_kb(), 0);
    EXPECT_GE(process_memory_usage.minflt(), 0);
    EXPECT_GE(process_memory_usage.majflt(), 0);

    // If cgroup memory events are collected, verify whether the contents are valid.
    if (memory_usage_event.has_cgroup_memory_usage()) {
      const CGroupMemoryUsage& cgroup_memory_usage = memory_usage_event.cgroup_memory_usage();
      EXPECT_FALSE(cgroup_memory_usage.cgroup_name().empty());
      timestamps.push_back(cgroup_memory_usage.timestamp_ns());
      EXPECT_GE(cgroup_memory_usage.limit_bytes(), 0);
      EXPECT_GE(cgroup_memory_usage.rss_bytes(), 0);
      EXPECT_GE(cgroup_memory_usage.mapped_file_bytes(), 0);
      EXPECT_GE(cgroup_memory_usage.pgfault(), 0);
      EXPECT_GE(cgroup_memory_usage.pgmajfault(), 0);
      EXPECT_GE(cgroup_memory_usage.unevictable_bytes(), 0);
      EXPECT_GE(cgroup_memory_usage.inactive_anon_bytes(), 0);
      EXPECT_GE(cgroup_memory_usage.active_anon_bytes(), 0);
      EXPECT_GE(cgroup_memory_usage.inactive_file_bytes(), 0);
      EXPECT_GE(cgroup_memory_usage.active_file_bytes(), 0);
    }

    // Verify that the memory events in the same memory_usage_event are sampled at very close time.
    uint64_t max_timestamp = *std::max_element(timestamps.begin(), timestamps.end());
    uint64_t min_timestamp = *std::min_element(timestamps.begin(), timestamps.end());
    EXPECT_LE(max_timestamp - min_timestamp, kMemoryEventsTimeDifferenceTolerace);
  }
}

// Verify whether the memory_sampling_period_ns_ works as expected by checking the number of
// received events.
void VerifyEventCounts(const std::vector<ProducerCaptureEvent>& events, size_t expected_counts) {
  constexpr size_t kEventCountsErrorTolerance = 2;

  size_t num_received_events = 0;
  for (const auto& event : events) {
    if (event.event_case() == ProducerCaptureEvent::kMemoryUsageEvent) num_received_events++;
  }

  EXPECT_GE(num_received_events, expected_counts - kEventCountsErrorTolerance);
}

}  // namespace

TEST(MemoryTracingIntegrationTest, MemoryTracing) {
  const uint64_t kMemorySamplingPeriodNs = absl::Milliseconds(100) / absl::Nanoseconds(1);
  const size_t kPeriodCounts = 10;

  MemoryTracingIntegrationTestFixture fixture(kMemorySamplingPeriodNs);

  absl::Duration tracing_period = absl::Nanoseconds(kMemorySamplingPeriodNs * kPeriodCounts);
  std::vector<ProducerCaptureEvent> events = TraceAndGetEvents(&fixture, tracing_period);

  VerifyOrderAndContentOfEvents(events, kMemorySamplingPeriodNs);

  VerifyEventCounts(events, kPeriodCounts);
}

}  // namespace orbit_memory_tracing<|endoftext|>


<commit_before>/* Siconos-Kernel, Copyright INRIA 2005-2010.
 * Siconos is a program dedicated to modeling, simulation and control
 * of non smooth dynamical systems.
 * Siconos is a free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 * Siconos is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with Siconos; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 *
 * Contact: Vincent ACARY, siconos-team@lists.gforge.inria.fr
 */
#include "DynamicalSystem.hpp"
#include "DynamicalSystemXML.hpp"
#include "BlockVector.hpp"
#include "Plugin.hpp"

using namespace std;

unsigned int DynamicalSystem::count = 0;

// ===== CONSTRUCTORS =====

// Default constructor (protected)
DynamicalSystem::DynamicalSystem():
  _number(count++), _n(0), _stepsInMemory(1)
{
  zeroPlugin();
  _normRef = 1;
  _x.resize(2);
  _workV.resize(sizeWorkV);
}

// From XML file
DynamicalSystem::DynamicalSystem(SP::DynamicalSystemXML dsXML):
  _number(dsXML->number()), _n(0), _stepsInMemory(1), _dsxml(dsXML)
{
  _normRef = 1;
  assert(dsXML && "DynamicalSystem::DynamicalSystem - DynamicalSystemXML paramater must not be NULL");

  // Update count: must be at least equal to number for future DS creation
  count = number();
  zeroPlugin();
  // Only the following data are set in this general constructor:
  //  - DSTye
  //  - _number
  //  - z
  //  - stepsInMemory
  // All others are dependent of the derived class type.

  // === Initial conditions ===
  // Warning: n is set thanks to vector of initial conditions size. That will be set in derived classes constructor.

  _x.resize(2);

  // z - Optional parameter.
  if (_dsxml->hasz())
    _z.reset(new SimpleVector(_dsxml->getz()));

  if (_dsxml->hasStepsInMemory()) _stepsInMemory = _dsxml->getStepsInMemory();
  _workV.resize(sizeWorkV);
}

// From a minimum set of data
DynamicalSystem::DynamicalSystem(unsigned int newN):
  _number(count++), _n(newN), _stepsInMemory(1)
{
  zeroPlugin();
  _normRef = 1;
  _x.resize(2);
  _workV.resize(sizeWorkV);
  _residuFree.reset(new SimpleVector(getDim()));
  _r.reset(new SimpleVector(getDim()));
}

bool DynamicalSystem::checkDynamicalSystem()
{
  bool output = true;
  // n
  if (_n == 0)
  {
    RuntimeException::selfThrow("DynamicalSystem::checkDynamicalSystem - number of degrees of freedom is equal to 0.");
    output = false;
  }
  if (!_x0)
  {
    RuntimeException::selfThrow("DynamicalSystem::checkDynamicalSystem - x0 not set.");
    output = false;
  }
  return output;
}
void DynamicalSystem::zeroPlugin()
{
  _pluginJacgx.reset(new PluggedObject());
  _pluginJacxDotG.reset(new PluggedObject());
  _pluging.reset(new PluggedObject());
}
// Setters

void DynamicalSystem::setX0(const SiconosVector& newValue)
{
  // check dimensions ...
  if (newValue.size() != _n)
    RuntimeException::selfThrow("DynamicalSystem::setX0 - inconsistent sizes between x0 input and n - Maybe you forget to set n?");

  if (_x0)
    *_x0 = newValue;

  else
  {
    if (newValue.isBlock())
      _x0.reset(new BlockVector(newValue));
    else
      _x0.reset(new SimpleVector(newValue));
  }
  _normRef = _x0->norm2() + 1;
}

void DynamicalSystem::setX0Ptr(SP::SiconosVector newPtr)
{
  // check dimensions ...
  assert(newPtr->size() == _n && "DynamicalSystem::setX0Ptr - inconsistent sizes between x0 input and n - Maybe you forget to set n?");
  _x0 = newPtr;
  _normRef = _x0->norm2() + 1;
}

void DynamicalSystem::setX(const SiconosVector& newValue)
{
  // Warning: this only sets the value of x[0]
  // We suppose that both x and (*x)[0] are properly allocated.

  // check dimensions ...
  if (newValue.size() != _n)
    RuntimeException::selfThrow("DynamicalSystem::setX - inconsistent sizes between x input and n - Maybe you forget to set n?");

  if (! _x[0])
    _x[0].reset(new SimpleVector(newValue));
  else
    *(_x[0]) = newValue;
}

void DynamicalSystem::setXPtr(SP::SiconosVector newPtr)
{
  // Warning: this only sets the pointer x[0]

  // check dimensions ...
  if (newPtr->size() != _n)
    RuntimeException::selfThrow("DynamicalSystem::setXPtr - inconsistent sizes between x input and n - Maybe you forget to set n?");

  _x[0] = newPtr;
}

void DynamicalSystem::setRhs(const SiconosVector& newValue)
{
  // Warning: this only sets the value of x[1]

  // check dimensions ...
  if (newValue.size() != _n)
    RuntimeException::selfThrow("DynamicalSystem::setRhs - inconsistent sizes between x input and n - Maybe you forget to set n?");

  if (! _x[1])
    _x[1].reset(new SimpleVector(newValue));
  else
    *(_x[1]) = newValue;
}

void DynamicalSystem::setRhsPtr(SP::SiconosVector newPtr)
{
  // Warning: this only sets the pointer (*x)[1]

  // check dimensions ...
  if (newPtr->size() != _n)
    RuntimeException::selfThrow("DynamicalSystem::setRhsPtr - inconsistent sizes between x input and n - Maybe you forget to set n?");

  _x[1] = newPtr;
}
void DynamicalSystem::setR(const SiconosVector& newValue)
{
  // check dimensions ...
  if (newValue.size() != _n)
    RuntimeException::selfThrow("DynamicalSystem::setR - inconsistent sizes between x0 input and n - Maybe you forget to set n?");

  if (_r)
    *_r = newValue;

  else
    _r.reset(new SimpleVector(newValue));
}

void DynamicalSystem::setRPtr(SP::SiconosVector newPtr)
{
  // check dimensions ...
  if (newPtr->size() != _n)
    RuntimeException::selfThrow("DynamicalSystem::setRPtr - inconsistent sizes between x0 input and n - Maybe you forget to set n?");

  _r = newPtr;

}

void DynamicalSystem::setJacobianRhsx(const SiconosMatrix& newValue)
{
  // check dimensions ...
  if (newValue.size(0) != _n || newValue.size(1) != _n)
    RuntimeException::selfThrow("DynamicalSystem::setJacobianRhsx - inconsistent sizes between jacobianRhsx input and n - Maybe you forget to set n?");

  if (_jacxRhs)
    *_jacxRhs = newValue;

  else
    _jacxRhs.reset(new SimpleMatrix(newValue));
}

void DynamicalSystem::setJacobianRhsxPtr(SP::SiconosMatrix newPtr)
{
  // check dimensions ...
  if (newPtr->size(0) != _n || newPtr->size(1) != _n)
    RuntimeException::selfThrow("DynamicalSystem::setJacobianRhsxPtr - inconsistent sizes between _jacxRhs input and n - Maybe you forget to set n?");

  _jacxRhs = newPtr;
}

void DynamicalSystem::setz(const SiconosVector& newValue)
{
  if (_z)
  {
    if (newValue.size() != _z->size())
      RuntimeException::selfThrow("DynamicalSystem::setz - inconsistent sizes between input and existing z - To change z size use setzPtr.");
    *_z = newValue;
  }
  else
  {

    if (newValue.isBlock())
      _z.reset(new BlockVector(newValue));
    else
      _z.reset(new SimpleVector(newValue));
  }
}

void DynamicalSystem::setzPtr(SP::SiconosVector newPtr)
{
  _z = newPtr;
}
/*
void DynamicalSystem::setG(const PVFInt& newValue)
{
  assert(newValue.size()==n&&"DynamicalSystem - setG: inconsistent dimensions with problem size for input vector g");

  if( !g  )
    g.reset(new PVFInt(newValue));
  else
    *g = newValue;
}
*/
/*
void DynamicalSystem::setJacobianG(unsigned int i, const PMFInt& newValue)
{
  assert(newValue.size(0)==n&&"DynamicalSystem - setJacobianG: inconsistent dimensions with problem size for matrix jacobianG.");
  assert(newValue.size(1)==n&&"DynamicalSystem - setJacobianG: inconsistent dimensions with problem size for matrix jacobianG.");

  if( !jacobianG [i] )
    jacobianG[i].reset(new PMFInt(newValue));
  else
    *jacobianG[i] = newValue;
}
*/

void DynamicalSystem::update(double time)
{
  computeRhs(time);
  computeJacobianRhsx(time);
}

// ===== MEMORY MANAGEMENT FUNCTIONS =====

void DynamicalSystem::initMemory(unsigned int steps)
{
  if (steps == 0)
    cout << "Warning : FirstOrderNonLinearDS::initMemory with size equal to zero" << endl;
  else
  {
    _stepsInMemory = steps;
    _xMemory.reset(new SiconosMemory(steps));

  }
}

void DynamicalSystem::setComputegFunction(const string& pluginPath, const string& functionName)
{
  _pluging->setComputeFunction(pluginPath, functionName);
}

void DynamicalSystem::setComputegFunction(FPtr6 fct)
{
  _pluging->setComputeFunction((void *)fct);
}

void DynamicalSystem::setComputeJacobianXGFunction(const string& pluginPath, const string& functionName)
{
  _pluginJacgx->setComputeFunction(pluginPath, functionName);
}
void DynamicalSystem::setComputeJacobianDotXGFunction(const string& pluginPath, const string& functionName)
{
  _pluginJacxDotG->setComputeFunction(pluginPath, functionName);
}
// void DynamicalSystem::setComputeJacobianZGFunction( const string& pluginPath, const string& functionName){
//   Plugin::setFunction(&pluginJacobianZGPtr, pluginPath,functionName);
// }

void DynamicalSystem::computeg(double time)
{
  if (_pluging->fPtr)
    ((FPtr6)(_pluging->fPtr))(time, _n, &(*_x[0])(0), &(*_x[1])(0), &(*_g)(0), _z->size(), &(*_z)(0));
}

void DynamicalSystem::computeJacobianXG(double time)
{
  if (_pluginJacgx->fPtr)
    ((FPtr6) _pluginJacgx->fPtr)(time, _n, &(*_x[0])(0), &(*_x[1])(0), &(*_jacgx)(0, 0), _z->size(), &(*_z)(0));
}
void DynamicalSystem::computeJacobianDotXG(double time)
{
  if (_pluginJacxDotG->fPtr)
    ((FPtr6)(_pluginJacxDotG->fPtr))(time, _n, &(*_x[0])(0), &(*_x[1])(0), &(*_jacxDotG)(0, 0), _z->size(), &(*_z)(0));
}
// void DynamicalSystem::computeJacobianZG(double time){
//   if (pluginJacobianXGPtr)
//     pluginJacobianZGPtr(time, n, &(*x[0])(0), &(*x[1])(0), &(*jacobianG[i])(0,0), z->size(), &(*z)(0));
// }

// ===== XML MANAGEMENT FUNCTIONS =====

void DynamicalSystem::saveDSToXML()
{
  RuntimeException::selfThrow("DynamicalSystem::saveDSToXML - Not yet tested for DS: do not use it.");

  if (!_dsxml)
    RuntimeException::selfThrow("DynamicalSystem::saveDSToXML - The DynamicalSystemXML object doesn't exists");

  // --- Specific (depending on derived class) DS data ---
  saveSpecificDataToXML();

  // --- other data ---
}

// ===== MISCELLANEOUS ====

double DynamicalSystem::dsConvergenceIndicator()
{
  RuntimeException::selfThrow
  ("DynamicalSystem:dsConvergenceIndicator - not yet implemented for this Dynamical system type");
  return 1.0;
}

<commit_msg>not first order<commit_after>/* Siconos-Kernel, Copyright INRIA 2005-2010.
 * Siconos is a program dedicated to modeling, simulation and control
 * of non smooth dynamical systems.
 * Siconos is a free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 * Siconos is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with Siconos; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 *
 * Contact: Vincent ACARY, siconos-team@lists.gforge.inria.fr
 */
#include "DynamicalSystem.hpp"
#include "DynamicalSystemXML.hpp"
#include "BlockVector.hpp"
#include "Plugin.hpp"

using namespace std;

unsigned int DynamicalSystem::count = 0;

// ===== CONSTRUCTORS =====

// Default constructor (protected)
DynamicalSystem::DynamicalSystem():
  _number(count++), _n(0), _stepsInMemory(1)
{
  zeroPlugin();
  _normRef = 1;
  _x.resize(2);
  _workV.resize(sizeWorkV);
}

// From XML file
DynamicalSystem::DynamicalSystem(SP::DynamicalSystemXML dsXML):
  _number(dsXML->number()), _n(0), _stepsInMemory(1), _dsxml(dsXML)
{
  _normRef = 1;
  assert(dsXML && "DynamicalSystem::DynamicalSystem - DynamicalSystemXML paramater must not be NULL");

  // Update count: must be at least equal to number for future DS creation
  count = number();
  zeroPlugin();
  // Only the following data are set in this general constructor:
  //  - DSTye
  //  - _number
  //  - z
  //  - stepsInMemory
  // All others are dependent of the derived class type.

  // === Initial conditions ===
  // Warning: n is set thanks to vector of initial conditions size. That will be set in derived classes constructor.

  _x.resize(2);

  // z - Optional parameter.
  if (_dsxml->hasz())
    _z.reset(new SimpleVector(_dsxml->getz()));

  if (_dsxml->hasStepsInMemory()) _stepsInMemory = _dsxml->getStepsInMemory();
  _workV.resize(sizeWorkV);
}

// From a minimum set of data
DynamicalSystem::DynamicalSystem(unsigned int newN):
  _number(count++), _n(newN), _stepsInMemory(1)
{
  zeroPlugin();
  _normRef = 1;
  _x.resize(2);
  _workV.resize(sizeWorkV);
  _residuFree.reset(new SimpleVector(getDim()));
  _r.reset(new SimpleVector(getDim()));
}

bool DynamicalSystem::checkDynamicalSystem()
{
  bool output = true;
  // n
  if (_n == 0)
  {
    RuntimeException::selfThrow("DynamicalSystem::checkDynamicalSystem - number of degrees of freedom is equal to 0.");
    output = false;
  }
  if (!_x0)
  {
    RuntimeException::selfThrow("DynamicalSystem::checkDynamicalSystem - x0 not set.");
    output = false;
  }
  return output;
}
void DynamicalSystem::zeroPlugin()
{
  _pluginJacgx.reset(new PluggedObject());
  _pluginJacxDotG.reset(new PluggedObject());
  _pluging.reset(new PluggedObject());
}
// Setters

void DynamicalSystem::setX0(const SiconosVector& newValue)
{
  // check dimensions ...
  if (newValue.size() != _n)
    RuntimeException::selfThrow("DynamicalSystem::setX0 - inconsistent sizes between x0 input and n - Maybe you forget to set n?");

  if (_x0)
    *_x0 = newValue;

  else
  {
    if (newValue.isBlock())
      _x0.reset(new BlockVector(newValue));
    else
      _x0.reset(new SimpleVector(newValue));
  }
  _normRef = _x0->norm2() + 1;
}

void DynamicalSystem::setX0Ptr(SP::SiconosVector newPtr)
{
  // check dimensions ...
  assert(newPtr->size() == _n && "DynamicalSystem::setX0Ptr - inconsistent sizes between x0 input and n - Maybe you forget to set n?");
  _x0 = newPtr;
  _normRef = _x0->norm2() + 1;
}

void DynamicalSystem::setX(const SiconosVector& newValue)
{
  // Warning: this only sets the value of x[0]
  // We suppose that both x and (*x)[0] are properly allocated.

  // check dimensions ...
  if (newValue.size() != _n)
    RuntimeException::selfThrow("DynamicalSystem::setX - inconsistent sizes between x input and n - Maybe you forget to set n?");

  if (! _x[0])
    _x[0].reset(new SimpleVector(newValue));
  else
    *(_x[0]) = newValue;
}

void DynamicalSystem::setXPtr(SP::SiconosVector newPtr)
{
  // Warning: this only sets the pointer x[0]

  // check dimensions ...
  if (newPtr->size() != _n)
    RuntimeException::selfThrow("DynamicalSystem::setXPtr - inconsistent sizes between x input and n - Maybe you forget to set n?");

  _x[0] = newPtr;
}

void DynamicalSystem::setRhs(const SiconosVector& newValue)
{
  // Warning: this only sets the value of x[1]

  // check dimensions ...
  if (newValue.size() != _n)
    RuntimeException::selfThrow("DynamicalSystem::setRhs - inconsistent sizes between x input and n - Maybe you forget to set n?");

  if (! _x[1])
    _x[1].reset(new SimpleVector(newValue));
  else
    *(_x[1]) = newValue;
}

void DynamicalSystem::setRhsPtr(SP::SiconosVector newPtr)
{
  // Warning: this only sets the pointer (*x)[1]

  // check dimensions ...
  if (newPtr->size() != _n)
    RuntimeException::selfThrow("DynamicalSystem::setRhsPtr - inconsistent sizes between x input and n - Maybe you forget to set n?");

  _x[1] = newPtr;
}
void DynamicalSystem::setR(const SiconosVector& newValue)
{
  // check dimensions ...
  if (newValue.size() != _n)
    RuntimeException::selfThrow("DynamicalSystem::setR - inconsistent sizes between x0 input and n - Maybe you forget to set n?");

  if (_r)
    *_r = newValue;

  else
    _r.reset(new SimpleVector(newValue));
}

void DynamicalSystem::setRPtr(SP::SiconosVector newPtr)
{
  // check dimensions ...
  if (newPtr->size() != _n)
    RuntimeException::selfThrow("DynamicalSystem::setRPtr - inconsistent sizes between x0 input and n - Maybe you forget to set n?");

  _r = newPtr;

}

void DynamicalSystem::setJacobianRhsx(const SiconosMatrix& newValue)
{
  // check dimensions ...
  if (newValue.size(0) != _n || newValue.size(1) != _n)
    RuntimeException::selfThrow("DynamicalSystem::setJacobianRhsx - inconsistent sizes between jacobianRhsx input and n - Maybe you forget to set n?");

  if (_jacxRhs)
    *_jacxRhs = newValue;

  else
    _jacxRhs.reset(new SimpleMatrix(newValue));
}

void DynamicalSystem::setJacobianRhsxPtr(SP::SiconosMatrix newPtr)
{
  // check dimensions ...
  if (newPtr->size(0) != _n || newPtr->size(1) != _n)
    RuntimeException::selfThrow("DynamicalSystem::setJacobianRhsxPtr - inconsistent sizes between _jacxRhs input and n - Maybe you forget to set n?");

  _jacxRhs = newPtr;
}

void DynamicalSystem::setz(const SiconosVector& newValue)
{
  if (_z)
  {
    if (newValue.size() != _z->size())
      RuntimeException::selfThrow("DynamicalSystem::setz - inconsistent sizes between input and existing z - To change z size use setzPtr.");
    *_z = newValue;
  }
  else
  {

    if (newValue.isBlock())
      _z.reset(new BlockVector(newValue));
    else
      _z.reset(new SimpleVector(newValue));
  }
}

void DynamicalSystem::setzPtr(SP::SiconosVector newPtr)
{
  _z = newPtr;
}
/*
void DynamicalSystem::setG(const PVFInt& newValue)
{
  assert(newValue.size()==n&&"DynamicalSystem - setG: inconsistent dimensions with problem size for input vector g");

  if( !g  )
    g.reset(new PVFInt(newValue));
  else
    *g = newValue;
}
*/
/*
void DynamicalSystem::setJacobianG(unsigned int i, const PMFInt& newValue)
{
  assert(newValue.size(0)==n&&"DynamicalSystem - setJacobianG: inconsistent dimensions with problem size for matrix jacobianG.");
  assert(newValue.size(1)==n&&"DynamicalSystem - setJacobianG: inconsistent dimensions with problem size for matrix jacobianG.");

  if( !jacobianG [i] )
    jacobianG[i].reset(new PMFInt(newValue));
  else
    *jacobianG[i] = newValue;
}
*/

void DynamicalSystem::update(double time)
{
  computeRhs(time);
  computeJacobianRhsx(time);
}

// ===== MEMORY MANAGEMENT FUNCTIONS =====

void DynamicalSystem::initMemory(unsigned int steps)
{
  if (steps == 0)
    cout << "Warning : initMemory with size equal to zero" << endl;
  else
  {
    _stepsInMemory = steps;
    _xMemory.reset(new SiconosMemory(steps));

  }
}

void DynamicalSystem::setComputegFunction(const string& pluginPath, const string& functionName)
{
  _pluging->setComputeFunction(pluginPath, functionName);
}

void DynamicalSystem::setComputegFunction(FPtr6 fct)
{
  _pluging->setComputeFunction((void *)fct);
}

void DynamicalSystem::setComputeJacobianXGFunction(const string& pluginPath, const string& functionName)
{
  _pluginJacgx->setComputeFunction(pluginPath, functionName);
}
void DynamicalSystem::setComputeJacobianDotXGFunction(const string& pluginPath, const string& functionName)
{
  _pluginJacxDotG->setComputeFunction(pluginPath, functionName);
}
// void DynamicalSystem::setComputeJacobianZGFunction( const string& pluginPath, const string& functionName){
//   Plugin::setFunction(&pluginJacobianZGPtr, pluginPath,functionName);
// }

void DynamicalSystem::computeg(double time)
{
  if (_pluging->fPtr)
    ((FPtr6)(_pluging->fPtr))(time, _n, &(*_x[0])(0), &(*_x[1])(0), &(*_g)(0), _z->size(), &(*_z)(0));
}

void DynamicalSystem::computeJacobianXG(double time)
{
  if (_pluginJacgx->fPtr)
    ((FPtr6) _pluginJacgx->fPtr)(time, _n, &(*_x[0])(0), &(*_x[1])(0), &(*_jacgx)(0, 0), _z->size(), &(*_z)(0));
}
void DynamicalSystem::computeJacobianDotXG(double time)
{
  if (_pluginJacxDotG->fPtr)
    ((FPtr6)(_pluginJacxDotG->fPtr))(time, _n, &(*_x[0])(0), &(*_x[1])(0), &(*_jacxDotG)(0, 0), _z->size(), &(*_z)(0));
}
// void DynamicalSystem::computeJacobianZG(double time){
//   if (pluginJacobianXGPtr)
//     pluginJacobianZGPtr(time, n, &(*x[0])(0), &(*x[1])(0), &(*jacobianG[i])(0,0), z->size(), &(*z)(0));
// }

// ===== XML MANAGEMENT FUNCTIONS =====

void DynamicalSystem::saveDSToXML()
{
  RuntimeException::selfThrow("DynamicalSystem::saveDSToXML - Not yet tested for DS: do not use it.");

  if (!_dsxml)
    RuntimeException::selfThrow("DynamicalSystem::saveDSToXML - The DynamicalSystemXML object doesn't exists");

  // --- Specific (depending on derived class) DS data ---
  saveSpecificDataToXML();

  // --- other data ---
}

// ===== MISCELLANEOUS ====

double DynamicalSystem::dsConvergenceIndicator()
{
  RuntimeException::selfThrow
  ("DynamicalSystem:dsConvergenceIndicator - not yet implemented for this Dynamical system type");
  return 1.0;
}

<|endoftext|>


<commit_before>/*************************************************************************
 *
 *  $RCSfile: docstyle.hxx,v $
 *
 *  $Revision: 1.2 $
 *
 *  last change: $Author: fme $ $Date: 2001-07-24 11:38:16 $
 *
 *  The Contents of this file are made available subject to the terms of
 *  either of the following licenses
 *
 *         - GNU Lesser General Public License Version 2.1
 *         - Sun Industry Standards Source License Version 1.1
 *
 *  Sun Microsystems Inc., October, 2000
 *
 *  GNU Lesser General Public License Version 2.1
 *  =============================================
 *  Copyright 2000 by Sun Microsystems, Inc.
 *  901 San Antonio Road, Palo Alto, CA 94303, USA
 *
 *  This library is free software; you can redistribute it and/or
 *  modify it under the terms of the GNU Lesser General Public
 *  License version 2.1, as published by the Free Software Foundation.
 *
 *  This library is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 *  Lesser General Public License for more details.
 *
 *  You should have received a copy of the GNU Lesser General Public
 *  License along with this library; if not, write to the Free Software
 *  Foundation, Inc., 59 Temple Place, Suite 330, Boston,
 *  MA  02111-1307  USA
 *
 *
 *  Sun Industry Standards Source License Version 1.1
 *  =================================================
 *  The contents of this file are subject to the Sun Industry Standards
 *  Source License Version 1.1 (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.openoffice.org/license.html.
 *
 *  Software provided under this License is provided on an "AS IS" basis,
 *  WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING,
 *  WITHOUT LIMITATION, WARRANTIES THAT THE SOFTWARE IS FREE OF DEFECTS,
 *  MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE, OR NON-INFRINGING.
 *  See the License for the specific provisions governing your rights and
 *  obligations concerning the Software.
 *
 *  The Initial Developer of the Original Code is: Sun Microsystems, Inc.
 *
 *  Copyright: 2000 by Sun Microsystems, Inc.
 *
 *  All Rights Reserved.
 *
 *  Contributor(s): _______________________________________
 *
 *
 ************************************************************************/
#ifndef _DOCSTYLE_HXX
#define _DOCSTYLE_HXX

#ifndef _SVSTDARR_HXX
#define _SVSTDARR_STRINGSDTOR
#include <svtools/svstdarr.hxx>
#endif

#ifndef _SFXSTYLE_HXX //autogen
#include <svtools/style.hxx>
#endif

#ifndef _SFXITEMSET_HXX //autogen
#include <svtools/itemset.hxx>
#endif

class SwDoc;
class SwDocStyleSheetPool;
class SwPageDesc;
class SwCharFmt;
class SwTxtFmtColl;
class SwFrmFmt;
class SwNumRule;

/*--------------------------------------------------------------------
    Beschreibung:   Lokale Hilfsklasse
 --------------------------------------------------------------------*/
class SwPoolFmtList : public SvStringsDtor
{
public:
    SwPoolFmtList() {}
    void Append( char cChar, const String& rStr );
    void Erase();
};

/*--------------------------------------------------------------------
    Beschreibung:   temp. StyleSheet
 --------------------------------------------------------------------*/
class SwDocStyleSheet : public SfxStyleSheetBase
{
    friend class SwDocStyleSheetPool;
    friend class SwStyleSheetIterator;

    SwCharFmt*          pCharFmt;
    SwTxtFmtColl*       pColl;
    SwFrmFmt*           pFrmFmt;
    const SwPageDesc*   pDesc;
    const SwNumRule*    pNumRule;

    SwDoc&              rDoc;
    SfxItemSet          aCoreSet;

    BOOL                bPhysical;

    // leere Huelse zum richtigen StyleSheet (Core) machen
    void                Create();

    // den StyleSheet mit Daten fuellen
    enum FillStyleType {
        FillOnlyName,
        FillAllInfo,
        FillPhysical
    };
    BOOL                FillStyleSheet( FillStyleType eFType );

public:
    SwDocStyleSheet( SwDoc&                 rDoc,
                     const String&          rName,
                     SwDocStyleSheetPool&   rPool,
                     SfxStyleFamily         eFam,
                     USHORT                 nMask);

    SwDocStyleSheet( const SwDocStyleSheet& );
    virtual ~SwDocStyleSheet();

    void                    Reset();

    void                    SetMask(USHORT nMsk)            { nMask = nMsk;     }
    void                    SetFamily(SfxStyleFamily eFam)  { nFamily = eFam;   }

    BOOL                    IsPhysical() const              { return bPhysical; }
    void                    SetPhysical(BOOL bPhys);

    void                    SetItemSet(const SfxItemSet& rSet);

    virtual SfxItemSet&     GetItemSet();
    virtual const String&   GetParent() const;
    virtual const String&   GetFollow() const;

    virtual ULONG GetHelpId( String& rFile );
    virtual void SetHelpId( const String& r, ULONG nId );

    // Vorbelegen der member ohne physikalischen Zugriff
    // wird vom StyleSheetPool benutzt
    //
    void                    PresetName(const String& rName)  { aName   = rName; }
    void                    PresetNameAndFamily(const String& rName);
    void                    PresetParent(const String& rName){ aParent = rName; }
    void                    PresetFollow(const String& rName){ aFollow = rName; }

    virtual BOOL            SetName( const String& rStr);
    virtual BOOL            SetParent( const String& rStr);
    virtual BOOL            SetFollow( const String& rStr);

    virtual BOOL            HasFollowSupport() const;
    virtual BOOL            HasParentSupport() const;
    virtual BOOL            HasClearParentSupport() const;
    virtual String          GetDescription();
    virtual String          GetDescription(SfxMapUnit eUnit);

    SwCharFmt*              GetCharFmt();
    SwTxtFmtColl*           GetCollection();
    SwFrmFmt*               GetFrmFmt();
    const SwPageDesc*       GetPageDesc();
    const SwNumRule*        GetNumRule();
    void                    SetNumRule(const SwNumRule& rRule);

    virtual BOOL            IsUsed() const;
};

/*--------------------------------------------------------------------
    Beschreibung:   Iterator fuer den Pool
 --------------------------------------------------------------------*/

class SwStyleSheetIterator : public SfxStyleSheetIterator, public SfxListener
{
    SwDocStyleSheet     aIterSheet;
    SwDocStyleSheet     aStyleSheet;
    SwPoolFmtList       aLst;
    USHORT              nLastPos;
    BOOL                bFirstCalled;

    void                AppendStyleList(const SvStringsDtor& rLst,
                                        BOOL    bUsed,
                                        USHORT  nSection,
                                        char    cType);

public:
    SwStyleSheetIterator( SwDocStyleSheetPool* pBase,
                          SfxStyleFamily eFam, USHORT n=0xFFFF );
    virtual ~SwStyleSheetIterator();

    virtual USHORT Count();
    virtual SfxStyleSheetBase *operator[](USHORT nIdx);
    virtual SfxStyleSheetBase* First();
    virtual SfxStyleSheetBase* Next();
    virtual SfxStyleSheetBase* Find(const UniString& rStr);

    virtual void Notify( SfxBroadcaster&, const SfxHint& );
};

/*--------------------------------------------------------------------
    Beschreibung:   Pool fuer
 --------------------------------------------------------------------*/

class SwDocStyleSheetPool : public SfxStyleSheetBasePool
{
    SwDocStyleSheet     aStyleSheet;
    SwDoc&              rDoc;
    BOOL                bOrganizer : 1;     // TRUE: fuer den Organizer

    virtual SfxStyleSheetBase* Create( const String&, SfxStyleFamily, USHORT nMask);
    virtual SfxStyleSheetBase* Create( const SfxStyleSheetBase& );
public:
    SwDocStyleSheetPool( SwDoc&, BOOL bOrganizer = FALSE );
    virtual ~SwDocStyleSheetPool();

    virtual void Replace( SfxStyleSheetBase& rSource,
                          SfxStyleSheetBase& rTarget );
    virtual SfxStyleSheetBase& Make(const String&, SfxStyleFamily, USHORT nMask, USHORT nPos = 0xffff);
    virtual SfxStyleSheetBase* Find( const String&, SfxStyleFamily eFam,
                                    USHORT n=0xFFFF );
    virtual BOOL SetParent( SfxStyleFamily eFam, const String &rStyle,
                            const String &rParent );

    virtual void Erase( SfxStyleSheetBase* pStyle);
    void    SetItemSet(const SfxItemSet& rSet) { aStyleSheet.SetItemSet(rSet); }

    void    SetOrganizerMode( BOOL bMode )  { bOrganizer = bMode; }
    BOOL    IsOrganizerMode() const         { return bOrganizer; }

    virtual SfxStyleSheetIterator* CreateIterator( SfxStyleFamily,
                                                    USHORT nMask );

    SwDoc& GetDoc() const { return rDoc; }

    //Fuer die daemlicheren Compiler
private:
    SwDocStyleSheetPool( const SwDocStyleSheetPool& );
};

#endif
<commit_msg>INTEGRATION: CWS tune03 (1.2.772); FILE MERGED 2004/07/19 19:10:31 mhu 1.2.772.1: #i29979# Added SW_DLLPUBLIC/PRIVATE (see swdllapi.h) to exported symbols/classes.<commit_after>/*************************************************************************
 *
 *  $RCSfile: docstyle.hxx,v $
 *
 *  $Revision: 1.3 $
 *
 *  last change: $Author: rt $ $Date: 2004-08-23 08:30:36 $
 *
 *  The Contents of this file are made available subject to the terms of
 *  either of the following licenses
 *
 *         - GNU Lesser General Public License Version 2.1
 *         - Sun Industry Standards Source License Version 1.1
 *
 *  Sun Microsystems Inc., October, 2000
 *
 *  GNU Lesser General Public License Version 2.1
 *  =============================================
 *  Copyright 2000 by Sun Microsystems, Inc.
 *  901 San Antonio Road, Palo Alto, CA 94303, USA
 *
 *  This library is free software; you can redistribute it and/or
 *  modify it under the terms of the GNU Lesser General Public
 *  License version 2.1, as published by the Free Software Foundation.
 *
 *  This library is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 *  Lesser General Public License for more details.
 *
 *  You should have received a copy of the GNU Lesser General Public
 *  License along with this library; if not, write to the Free Software
 *  Foundation, Inc., 59 Temple Place, Suite 330, Boston,
 *  MA  02111-1307  USA
 *
 *
 *  Sun Industry Standards Source License Version 1.1
 *  =================================================
 *  The contents of this file are subject to the Sun Industry Standards
 *  Source License Version 1.1 (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.openoffice.org/license.html.
 *
 *  Software provided under this License is provided on an "AS IS" basis,
 *  WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING,
 *  WITHOUT LIMITATION, WARRANTIES THAT THE SOFTWARE IS FREE OF DEFECTS,
 *  MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE, OR NON-INFRINGING.
 *  See the License for the specific provisions governing your rights and
 *  obligations concerning the Software.
 *
 *  The Initial Developer of the Original Code is: Sun Microsystems, Inc.
 *
 *  Copyright: 2000 by Sun Microsystems, Inc.
 *
 *  All Rights Reserved.
 *
 *  Contributor(s): _______________________________________
 *
 *
 ************************************************************************/
#ifndef _DOCSTYLE_HXX
#define _DOCSTYLE_HXX

#ifndef _SVSTDARR_HXX
#define _SVSTDARR_STRINGSDTOR
#include <svtools/svstdarr.hxx>
#endif

#ifndef _SFXSTYLE_HXX //autogen
#include <svtools/style.hxx>
#endif

#ifndef _SFXITEMSET_HXX //autogen
#include <svtools/itemset.hxx>
#endif

#ifndef INCLUDED_SWDLLAPI_H
#include "swdllapi.h"
#endif

class SwDoc;
class SwDocStyleSheetPool;
class SwPageDesc;
class SwCharFmt;
class SwTxtFmtColl;
class SwFrmFmt;
class SwNumRule;

/*--------------------------------------------------------------------
    Beschreibung:   Lokale Hilfsklasse
 --------------------------------------------------------------------*/
class SwPoolFmtList : public SvStringsDtor
{
public:
    SwPoolFmtList() {}
    void Append( char cChar, const String& rStr );
    void Erase();
};

/*--------------------------------------------------------------------
    Beschreibung:   temp. StyleSheet
 --------------------------------------------------------------------*/
class SW_DLLPUBLIC SwDocStyleSheet : public SfxStyleSheetBase
{
    friend class SwDocStyleSheetPool;
    friend class SwStyleSheetIterator;

    SwCharFmt*          pCharFmt;
    SwTxtFmtColl*       pColl;
    SwFrmFmt*           pFrmFmt;
    const SwPageDesc*   pDesc;
    const SwNumRule*    pNumRule;

    SwDoc&              rDoc;
    SfxItemSet          aCoreSet;

    BOOL                bPhysical;

    // leere Huelse zum richtigen StyleSheet (Core) machen
    SW_DLLPRIVATE void              Create();

    // den StyleSheet mit Daten fuellen
    enum FillStyleType {
        FillOnlyName,
        FillAllInfo,
        FillPhysical
    };

    SW_DLLPRIVATE BOOL FillStyleSheet( FillStyleType eFType );

public:
    SwDocStyleSheet( SwDoc&                 rDoc,
                     const String&          rName,
                     SwDocStyleSheetPool&   rPool,
                     SfxStyleFamily         eFam,
                     USHORT                 nMask);

    SwDocStyleSheet( const SwDocStyleSheet& );
    virtual ~SwDocStyleSheet();

    void                    Reset();

    void                    SetMask(USHORT nMsk)            { nMask = nMsk;     }
    void                    SetFamily(SfxStyleFamily eFam)  { nFamily = eFam;   }

    BOOL                    IsPhysical() const              { return bPhysical; }
    void                    SetPhysical(BOOL bPhys);

    void                    SetItemSet(const SfxItemSet& rSet);

    virtual SfxItemSet&     GetItemSet();
    virtual const String&   GetParent() const;
    virtual const String&   GetFollow() const;

    virtual ULONG GetHelpId( String& rFile );
    virtual void SetHelpId( const String& r, ULONG nId );

    // Vorbelegen der member ohne physikalischen Zugriff
    // wird vom StyleSheetPool benutzt
    //
    void                    PresetName(const String& rName)  { aName   = rName; }
    void                    PresetNameAndFamily(const String& rName);
    void                    PresetParent(const String& rName){ aParent = rName; }
    void                    PresetFollow(const String& rName){ aFollow = rName; }

    virtual BOOL            SetName( const String& rStr);
    virtual BOOL            SetParent( const String& rStr);
    virtual BOOL            SetFollow( const String& rStr);

    virtual BOOL            HasFollowSupport() const;
    virtual BOOL            HasParentSupport() const;
    virtual BOOL            HasClearParentSupport() const;
    virtual String          GetDescription();
    virtual String          GetDescription(SfxMapUnit eUnit);

    SwCharFmt*              GetCharFmt();
    SwTxtFmtColl*           GetCollection();
    SwFrmFmt*               GetFrmFmt();
    const SwPageDesc*       GetPageDesc();
    const SwNumRule*        GetNumRule();
    void                    SetNumRule(const SwNumRule& rRule);

    virtual BOOL            IsUsed() const;
};

/*--------------------------------------------------------------------
    Beschreibung:   Iterator fuer den Pool
 --------------------------------------------------------------------*/

class SwStyleSheetIterator : public SfxStyleSheetIterator, public SfxListener
{
    SwDocStyleSheet     aIterSheet;
    SwDocStyleSheet     aStyleSheet;
    SwPoolFmtList       aLst;
    USHORT              nLastPos;
    BOOL                bFirstCalled;

    void                AppendStyleList(const SvStringsDtor& rLst,
                                        BOOL    bUsed,
                                        USHORT  nSection,
                                        char    cType);

public:
    SwStyleSheetIterator( SwDocStyleSheetPool* pBase,
                          SfxStyleFamily eFam, USHORT n=0xFFFF );
    virtual ~SwStyleSheetIterator();

    virtual USHORT Count();
    virtual SfxStyleSheetBase *operator[](USHORT nIdx);
    virtual SfxStyleSheetBase* First();
    virtual SfxStyleSheetBase* Next();
    virtual SfxStyleSheetBase* Find(const UniString& rStr);

    virtual void Notify( SfxBroadcaster&, const SfxHint& );
};

/*--------------------------------------------------------------------
    Beschreibung:   Pool fuer
 --------------------------------------------------------------------*/

class SwDocStyleSheetPool : public SfxStyleSheetBasePool
{
    SwDocStyleSheet     aStyleSheet;
    SwDoc&              rDoc;
    BOOL                bOrganizer : 1;     // TRUE: fuer den Organizer

    virtual SfxStyleSheetBase* Create( const String&, SfxStyleFamily, USHORT nMask);
    virtual SfxStyleSheetBase* Create( const SfxStyleSheetBase& );
public:
    SwDocStyleSheetPool( SwDoc&, BOOL bOrganizer = FALSE );
    virtual ~SwDocStyleSheetPool();

    virtual void Replace( SfxStyleSheetBase& rSource,
                          SfxStyleSheetBase& rTarget );
    virtual SfxStyleSheetBase& Make(const String&, SfxStyleFamily, USHORT nMask, USHORT nPos = 0xffff);
    virtual SfxStyleSheetBase* Find( const String&, SfxStyleFamily eFam,
                                    USHORT n=0xFFFF );
    virtual BOOL SetParent( SfxStyleFamily eFam, const String &rStyle,
                            const String &rParent );

    virtual void Erase( SfxStyleSheetBase* pStyle);
    void    SetItemSet(const SfxItemSet& rSet) { aStyleSheet.SetItemSet(rSet); }

    void    SetOrganizerMode( BOOL bMode )  { bOrganizer = bMode; }
    BOOL    IsOrganizerMode() const         { return bOrganizer; }

    virtual SfxStyleSheetIterator* CreateIterator( SfxStyleFamily,
                                                    USHORT nMask );

    SwDoc& GetDoc() const { return rDoc; }

    //Fuer die daemlicheren Compiler
private:
    SwDocStyleSheetPool( const SwDocStyleSheetPool& );
};

#endif
<|endoftext|>


<commit_before>#ifndef ALEPH_TOPOLOGY_IO_MATRIX_HH__
#define ALEPH_TOPOLOGY_IO_MATRIX_HH__

#include <algorithm>
#include <fstream>
#include <istream>
#include <string>
#include <vector>

#include <aleph/utilities/String.hh>

namespace aleph
{

namespace topology
{

namespace io
{

/**
  @class BipartiteAdjacencyMatrixReader
  @brief Reads bipartite adjacency matrices in text format

  This reader class is meant to load bipartite adjacency matrices in
  text format. Every row of the matrix represents edges that connect
  nodes from the first class with nodes of the second class. Weights
  that are non-zero are used to indicate the presence of an edge.

  The number of rows and columns must not vary over the file. An *empty*
  line is permitted, though. Likewise, lines starting with `#` will just
  be ignored. An example of a 2-by-3 matrix follows:

  \code
  0 1 2
  3 4 5
  \endcode
*/

class BipartiteAdjacencyMatrixReader
{
public:

  /**
    Reads a simplicial complex from a file.

    @param filename Input filename
    @param  K       Simplicial complex
  */

  template <class SimplicialComplex> void operator()( const std::string& filename, SimplicialComplex& K )
  {
    std::ifstream in( filename );
    if( !in )
      throw std::runtime_error( "Unable to read input file" );

    this->operator()( filename, K );
  }

  /** @overload operator()( const std::string&, SimplicialComplex& ) */
  template <class SimplicialComplex> void operator()( std::istream& in, SimplicialComplex& K )
  {
    using Simplex    = typename SimplicialComplex::ValueType;
    using DataType   = typename Simplex::DataType;

    auto position = in.tellg();

    std::size_t height = 0;
    std::size_t width  = 0;

    using namespace aleph::utilities;

    {
      std::string line;
      while( std::getline( in, line ) )
      {
        line        = trim( line );
        auto tokens = split( line );

        if( width == 0 )
          width = tokens.size();
        else if( width != tokens.size() )
          throw std::runtime_error( "Format error: number of columns must not vary" );

        ++height;
      }

      in.clear();
      in.seekg( position );
    }

    _height = height;
    _width  = width;

    using Simplex    = typename SimplicialComplex::ValueType;
    using DataType   = typename Simplex::DataType;
    using VertexType = typename Simplex::VertexType;

    std::vector<DataType> values;
    values.reserve( _height * _width );

    std::copy( std::istream_iterator<DataType>( in ), std::istream_iterator<DataType>(),
               std::back_inserter( values ) );

    std::vector<Simplex> simplices;

    // Vertices --------------------------------------------------------
    //
    // Create a vertex for every node in the input data. An (n,m)-matrix
    // thus gives rise to n+m nodes.

    for( std::size_t i = 0; i < _height + _width; i++ )
      simplices.push_back( Simplex( VertexType( i ) ) );

    // Edges -----------------------------------------------------------
    //
    // Vertex indices start go from [0,rows-1] for the nodes of class one,
    // and from [rows,rows+columns] for the nodes of class two.

    for( std::size_t y = 0; y < _height; y++ )
    {
      for( std::size_t x = 0; x < _width; x++ )
      {
        auto i = static_cast<VertexType>( width * y + x   );
        auto w = values.at( i );

        // Map matrix indices to the corresponding vertex indices as
        // outline above.
        auto u = VertexType(y);
        auto v = VertexType(x + _height);

        simplices.push_back( Simplex( {u,v}, w ) );
      }
    }

    K = SimplicialComplex( simplices.begin(), simplices.end() );
  }

  /** @returns Height of matrix that was read last */
  std::size_t height() const noexcept { return _height; }

  /** @returns Width of matrix that was read last */
  std::size_t width()  const noexcept { return _width;  }

private:
  std::size_t _height = 0;
  std::size_t _width  = 0;
};

} // namespace io

} // namespace topology

} // namespace aleph

#endif
<commit_msg>Establishing filtration of simplicial complex<commit_after>#ifndef ALEPH_TOPOLOGY_IO_MATRIX_HH__
#define ALEPH_TOPOLOGY_IO_MATRIX_HH__

#include <algorithm>
#include <fstream>
#include <istream>
#include <string>
#include <vector>

#include <aleph/utilities/String.hh>

#include <aleph/topology/filtrations/Data.hh>

namespace aleph
{

namespace topology
{

namespace io
{

/**
  @class BipartiteAdjacencyMatrixReader
  @brief Reads bipartite adjacency matrices in text format

  This reader class is meant to load bipartite adjacency matrices in
  text format. Every row of the matrix represents edges that connect
  nodes from the first class with nodes of the second class. Weights
  that are non-zero are used to indicate the presence of an edge.

  The number of rows and columns must not vary over the file. An *empty*
  line is permitted, though. Likewise, lines starting with `#` will just
  be ignored. An example of a 2-by-3 matrix follows:

  \code
  0 1 2
  3 4 5
  \endcode

  All simplicial complexes created by this class will be reported
  in filtration order, following the detected weights.
*/

class BipartiteAdjacencyMatrixReader
{
public:

  /**
    Reads a simplicial complex from a file.

    @param filename Input filename
    @param  K       Simplicial complex
  */

  template <class SimplicialComplex> void operator()( const std::string& filename, SimplicialComplex& K )
  {
    std::ifstream in( filename );
    if( !in )
      throw std::runtime_error( "Unable to read input file" );

    this->operator()( filename, K );
  }

  /** @overload operator()( const std::string&, SimplicialComplex& ) */
  template <class SimplicialComplex> void operator()( std::istream& in, SimplicialComplex& K )
  {
    using Simplex    = typename SimplicialComplex::ValueType;
    using DataType   = typename Simplex::DataType;

    auto position = in.tellg();

    std::size_t height = 0;
    std::size_t width  = 0;

    using namespace aleph::utilities;

    {
      std::string line;
      while( std::getline( in, line ) )
      {
        line        = trim( line );
        auto tokens = split( line );

        if( width == 0 )
          width = tokens.size();
        else if( width != tokens.size() )
          throw std::runtime_error( "Format error: number of columns must not vary" );

        ++height;
      }

      in.clear();
      in.seekg( position );
    }

    _height = height;
    _width  = width;

    using Simplex    = typename SimplicialComplex::ValueType;
    using DataType   = typename Simplex::DataType;
    using VertexType = typename Simplex::VertexType;

    std::vector<DataType> values;
    values.reserve( _height * _width );

    std::copy( std::istream_iterator<DataType>( in ), std::istream_iterator<DataType>(),
               std::back_inserter( values ) );

    std::vector<Simplex> simplices;

    // Vertices --------------------------------------------------------
    //
    // Create a vertex for every node in the input data. An (n,m)-matrix
    // thus gives rise to n+m nodes.

    for( std::size_t i = 0; i < _height + _width; i++ )
      simplices.push_back( Simplex( VertexType( i ) ) );

    // Edges -----------------------------------------------------------
    //
    // Vertex indices start go from [0,rows-1] for the nodes of class one,
    // and from [rows,rows+columns] for the nodes of class two.

    for( std::size_t y = 0; y < _height; y++ )
    {
      for( std::size_t x = 0; x < _width; x++ )
      {
        auto i = static_cast<VertexType>( width * y + x   );
        auto w = values.at( i );

        // Map matrix indices to the corresponding vertex indices as
        // outline above.
        auto u = VertexType(y);
        auto v = VertexType(x + _height);

        simplices.push_back( Simplex( {u,v}, w ) );
      }
    }

    K = SimplicialComplex( simplices.begin(), simplices.end() );

    // Establish filtration order based on weights. There does not seem
    // to be much of a point to make this configurable; the edge weight
    // is a given property of the data.
    K.sort(
      filtrations::Data<Simplex>()
    );
  }

  /** @returns Height of matrix that was read last */
  std::size_t height() const noexcept { return _height; }

  /** @returns Width of matrix that was read last */
  std::size_t width()  const noexcept { return _width;  }

private:
  std::size_t _height = 0;
  std::size_t _width  = 0;
};

} // namespace io

} // namespace topology

} // namespace aleph

#endif
<|endoftext|>


<commit_before>/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/*
 * This file is part of the LibreOffice project.
 *
 * This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
 *
 * This file incorporates work covered by the following license notice:
 *
 *   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 .
 */

#ifndef INCLUDED_SVX_SDR_CONTACT_VIEWOBJECTCONTACTOFSDROBJ_HXX
#define INCLUDED_SVX_SDR_CONTACT_VIEWOBJECTCONTACTOFSDROBJ_HXX

#include <svx/sdr/contact/viewobjectcontact.hxx>
#include <boost/optional.hpp>

// predeclarations
class SdrObject;
class SetOfByte;
class OutputDevice;

namespace sdr
{
    namespace contact
    {
        class SVX_DLLPUBLIC ViewObjectContactOfSdrObj : public ViewObjectContact
        {
            /** Test whether the primitive is visible on any layer from @c aLayers

                This should be overridden by ViewObjectContacts of SDR classes
                that have subparts which can be on different layers (that is,
                SdrObjGroup .-)
              */
            virtual bool isPrimitiveVisibleOnAnyLayer(const SetOfByte& aLayers) const;

        protected:
            const SdrObject& getSdrObject() const;

        public:
            ViewObjectContactOfSdrObj(ObjectContact& rObjectContact, ViewContact& rViewContact);
            virtual ~ViewObjectContactOfSdrObj();

            virtual bool isPrimitiveVisible(const DisplayInfo& rDisplayInfo) const SAL_OVERRIDE;

            /** retrieves the device which a PageView belongs to, starting from its ObjectContactOfPageView

                Since #i72752#, the PaintWindow (and thus the OutputDevice) associated with a PageView is not
                constant over its lifetime. Instead, during some paint operations, the PaintWindow/OutputDevice
                might be temporarily patched.

                This method cares for this, by retrieving the very original OutputDevice.
            */
            boost::optional<const OutputDevice&> getPageViewOutputDevice() const;
        };
    } // end of namespace contact
} // end of namespace sdr

#endif // INCLUDED_SVX_SDR_CONTACT_VIEWOBJECTCONTACTOFSDROBJ_HXX

/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
<commit_msg>Unindent.<commit_after>/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/*
 * This file is part of the LibreOffice project.
 *
 * This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
 *
 * This file incorporates work covered by the following license notice:
 *
 *   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 .
 */

#ifndef INCLUDED_SVX_SDR_CONTACT_VIEWOBJECTCONTACTOFSDROBJ_HXX
#define INCLUDED_SVX_SDR_CONTACT_VIEWOBJECTCONTACTOFSDROBJ_HXX

#include <svx/sdr/contact/viewobjectcontact.hxx>
#include <boost/optional.hpp>

// predeclarations
class SdrObject;
class SetOfByte;
class OutputDevice;

namespace sdr { namespace contact {

class SVX_DLLPUBLIC ViewObjectContactOfSdrObj : public ViewObjectContact
{
    /** Test whether the primitive is visible on any layer from @c aLayers

        This should be overridden by ViewObjectContacts of SDR classes
        that have subparts which can be on different layers (that is,
        SdrObjGroup .-)
      */
    virtual bool isPrimitiveVisibleOnAnyLayer(const SetOfByte& aLayers) const;

protected:
    const SdrObject& getSdrObject() const;

public:
    ViewObjectContactOfSdrObj(ObjectContact& rObjectContact, ViewContact& rViewContact);
    virtual ~ViewObjectContactOfSdrObj();

    virtual bool isPrimitiveVisible(const DisplayInfo& rDisplayInfo) const SAL_OVERRIDE;

    /** retrieves the device which a PageView belongs to, starting from its ObjectContactOfPageView

        Since #i72752#, the PaintWindow (and thus the OutputDevice) associated with a PageView is not
        constant over its lifetime. Instead, during some paint operations, the PaintWindow/OutputDevice
        might be temporarily patched.

        This method cares for this, by retrieving the very original OutputDevice.
    */
    boost::optional<const OutputDevice&> getPageViewOutputDevice() const;
};

}}

#endif // INCLUDED_SVX_SDR_CONTACT_VIEWOBJECTCONTACTOFSDROBJ_HXX

/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
<|endoftext|>