<commit_before>// mail-enqueue - queue a mail message for delivery

#include "libutil.h"
#include "shutil.h"
#include "xsys.h"

#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/socket.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <sys/un.h>

#include <string>

using std::string;

class spool_writer
{
  string spooldir_;
  int notifyfd_;
  struct sockaddr_un notify_addr_;
  socklen_t notify_len_;

public:
  spool_writer(const string &spooldir) : spooldir_(spooldir), notify_addr_{}
  {
    notifyfd_ = socket(AF_UNIX, SOCK_DGRAM, 0);
    if (notifyfd_ < 0)
      edie("socket failed");

    notify_addr_.sun_family = AF_UNIX;
    snprintf(notify_addr_.sun_path, sizeof notify_addr_.sun_path,
             "%s/notify", spooldir.c_str());
    notify_len_ = SUN_LEN(&notify_addr_);
  }

  void queue(int msgfd, const char *recipient)
  {
    // Create temporary message
    char tmpname[256];
    snprintf(tmpname, sizeof tmpname,
             "%s/pid/%d", spooldir_.c_str(), getpid());
    int tmpfd = open(tmpname, O_CREAT|O_EXCL|O_WRONLY, 0600);
    if (tmpfd < 0)
      edie("open %s failed", tmpname);

    if (copy_fd(tmpfd, msgfd) < 0)
      edie("copy_fd message failed");

    struct stat st;
    if (fstatx(tmpfd, &st, STAT_OMIT_NLINK) < 0)
      edie("fstat failed");

    close(tmpfd);

    // Create envelope
    char envname[256];
    snprintf(envname, sizeof envname,
             "%s/todo/%lu", spooldir_.c_str(), (unsigned long)st.st_ino);
    int envfd = open(envname, O_CREAT|O_EXCL|O_WRONLY, 0600);
    if (envfd < 0)
      edie("open %s failed", envname);
    xwrite(envfd, recipient, strlen(recipient));
    close(envfd);

    // Move message into spool
    char msgname[256];
    snprintf(msgname, sizeof msgname,
             "%s/mess/%lu", spooldir_.c_str(), (unsigned long)st.st_ino);
    if (rename(tmpname, msgname) < 0)
      edie("rename %s %s failed", tmpname, msgname);

    // Notify queue manager.  We don't need an acknowledgment because
    // we've already "durably" queued the message.
    char notif[16];
    snprintf(notif, sizeof notif, "%lu", (unsigned long)st.st_ino);
    if (sendto(notifyfd_, notif, strlen(notif), 0,
               (struct sockaddr*)&notify_addr_, notify_len_) < 0)
      edie("send failed");
  }

  void queue_exit()
  {
    const char *msg = "EXIT";
    if (sendto(notifyfd_, msg, strlen(msg), 0,
               (struct sockaddr*)&notify_addr_, notify_len_) < 0)
      edie("send failed");
  }
};

static void
usage(const char *argv0)
{
  fprintf(stderr, "Usage: %s spooldir recipient <message\n", argv0);
  fprintf(stderr, "       %s --exit spooldir\n", argv0);
  exit(2);
}

int
main(int argc, char **argv)
{
  if (argc == 3 && strcmp(argv[1], "--exit") == 0) {
    spool_writer spool{argv[2]};
    spool.queue_exit();
    return 0;
  }

  if (argc != 3)
    usage(argv[0]);

  const char *spooldir = argv[1];
  const char *recip = argv[2];

  spool_writer spool{spooldir};
  spool.queue(0, recip);

  return 0;
}
<commit_msg>mail-enqueue: Support batch enqueuing<commit_after>// mail-enqueue - queue a mail message for delivery

#include "libutil.h"
#include "shutil.h"
#include "xsys.h"

#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/socket.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <sys/un.h>

#include <string>

using std::string;

class spool_writer
{
  string spooldir_;
  int notifyfd_;
  struct sockaddr_un notify_addr_;
  socklen_t notify_len_;

public:
  spool_writer(const string &spooldir) : spooldir_(spooldir), notify_addr_{}
  {
    notifyfd_ = socket(AF_UNIX, SOCK_DGRAM, 0);
    if (notifyfd_ < 0)
      edie("socket failed");

    notify_addr_.sun_family = AF_UNIX;
    snprintf(notify_addr_.sun_path, sizeof notify_addr_.sun_path,
             "%s/notify", spooldir.c_str());
    notify_len_ = SUN_LEN(&notify_addr_);
  }

  void queue(int msgfd, const char *recipient, size_t limit = (size_t)-1)
  {
    // Create temporary message
    char tmpname[256];
    snprintf(tmpname, sizeof tmpname,
             "%s/pid/%d", spooldir_.c_str(), getpid());
    int tmpfd = open(tmpname, O_CREAT|O_EXCL|O_WRONLY, 0600);
    if (tmpfd < 0)
      edie("open %s failed", tmpname);

    if (copy_fd_n(tmpfd, msgfd, limit) < 0)
      edie("copy_fd message failed");

    struct stat st;
    if (fstatx(tmpfd, &st, STAT_OMIT_NLINK) < 0)
      edie("fstat failed");

    close(tmpfd);

    // Create envelope
    char envname[256];
    snprintf(envname, sizeof envname,
             "%s/todo/%lu", spooldir_.c_str(), (unsigned long)st.st_ino);
    int envfd = open(envname, O_CREAT|O_EXCL|O_WRONLY, 0600);
    if (envfd < 0)
      edie("open %s failed", envname);
    xwrite(envfd, recipient, strlen(recipient));
    close(envfd);

    // Move message into spool
    char msgname[256];
    snprintf(msgname, sizeof msgname,
             "%s/mess/%lu", spooldir_.c_str(), (unsigned long)st.st_ino);
    if (rename(tmpname, msgname) < 0)
      edie("rename %s %s failed", tmpname, msgname);

    // Notify queue manager.  We don't need an acknowledgment because
    // we've already "durably" queued the message.
    char notif[16];
    snprintf(notif, sizeof notif, "%lu", (unsigned long)st.st_ino);
    if (sendto(notifyfd_, notif, strlen(notif), 0,
               (struct sockaddr*)&notify_addr_, notify_len_) < 0)
      edie("send failed");
  }

  void queue_exit()
  {
    const char *msg = "EXIT";
    if (sendto(notifyfd_, msg, strlen(msg), 0,
               (struct sockaddr*)&notify_addr_, notify_len_) < 0)
      edie("send failed");
  }
};

static void
do_batch_mode(int fd, const char *recip, spool_writer *spool)
{
  while (1) {
    uint64_t msg_len;
    size_t len = xread(fd, &msg_len, sizeof msg_len);
    if (len == 0)
      break;
    if (len != sizeof msg_len)
      die("short read of message length");
    spool->queue(fd, recip, msg_len);
  }
}

static void
usage(const char *argv0)
{
  fprintf(stderr, "Usage: %s spooldir recipient <message\n", argv0);
  fprintf(stderr, "       %s -b spooldir recipient <message-stream\n", argv0);
  fprintf(stderr, "       %s --exit spooldir\n", argv0);
  fprintf(stderr, "\n");
  fprintf(stderr, "Where message-stream is a sequence of <u64 N><char[N]>.");
  exit(2);
}

int
main(int argc, char **argv)
{
  if (argc == 3 && strcmp(argv[1], "--exit") == 0) {
    spool_writer spool{argv[2]};
    spool.queue_exit();
    return 0;
  }

  int opt;
  bool batch_mode = false;
  while ((opt = getopt(argc, argv, "b")) != -1) {
    switch (opt) {
    case 'b':
      batch_mode = true;
      break;
    default:
      usage(argv[0]);
    }
  }

  if (argc - optind != 2)
    usage(argv[0]);

  const char *spooldir = argv[optind];
  const char *recip = argv[optind + 1];

  spool_writer spool{spooldir};
  if (batch_mode)
    do_batch_mode(0, recip, &spool);
  else
    spool.queue(0, recip);

  return 0;
}
<|endoftext|>


<commit_before>/*************************************************/
/*  audio_driver_rtaudio.cpp                     */
/*************************************************/
/*            This file is part of:              */
/*                GODOT ENGINE                   */
/*************************************************/
/*       Source code within this file is:        */
/*  (c) 2007-2016 Juan Linietsky, Ariel Manzur   */
/*             All Rights Reserved.              */
/*************************************************/

#include "audio_driver_rtaudio.h"
#include "globals.h"
#include "os/os.h"
#ifdef RTAUDIO_ENABLED

const char* AudioDriverRtAudio::get_name() const {

#ifdef OSX_ENABLED
	return "RtAudio-OSX";
#elif defined(UNIX_ENABLED)
	return "RtAudio-ALSA";
#elif defined(WINDOWS_ENABLED)
	return "RtAudio-DirectSound";
#else
	return "RtAudio-None";
#endif

}

// Two-channel sawtooth wave generator.
int AudioDriverRtAudio::callback( void *outputBuffer, void *inputBuffer, unsigned int nBufferFrames,
	double streamTime, RtAudioStreamStatus status, void *userData ) {

	if (status)
		print_line("lost?");
	int32_t *buffer = (int32_t *) outputBuffer;

	AudioDriverRtAudio *self = (AudioDriverRtAudio*)userData;

	if (self->mutex->try_lock()!=OK) {

		// what should i do..
		for(unsigned int i=0;i<nBufferFrames;i++)
			buffer[i]=0;

		return 0;
	}

	self->audio_server_process(nBufferFrames,buffer);

	self->mutex->unlock();;

	return 0;
}

Error AudioDriverRtAudio::init() {

	active=false;
	mutex=NULL;
	dac = memnew( RtAudio );

	ERR_EXPLAIN("Cannot initialize RtAudio audio driver: No devices present.")
	ERR_FAIL_COND_V( dac->getDeviceCount() < 1, ERR_UNAVAILABLE );

	String channels = GLOBAL_DEF("audio/output","stereo");

	if (channels=="5.1")
		output_format=OUTPUT_5_1;
	else if (channels=="quad")
		output_format=OUTPUT_QUAD;
	else if (channels=="mono")
		output_format=OUTPUT_MONO;
	else
		output_format=OUTPUT_STEREO;

	RtAudio::StreamParameters parameters;
	parameters.deviceId = dac->getDefaultOutputDevice();
	RtAudio::StreamOptions options;
//	options.
//	RtAudioStreamFlags flags;      /*!< A bit-mask of stream flags (RTAUDIO_NONINTERLEAVED, RTAUDIO_MINIMIZE_LATENCY, RTAUDIO_HOG_DEVICE). *///
//	unsigned int numberOfBuffers;  /*!< Number of stream buffers. */
//	std::string streamName;        /*!< A stream name (currently used only in Jack). */
//	int priority;                  /*!< Scheduling priority of callback thread (only used with flag RTAUDIO_SCHEDULE_REALTIME). */

	parameters.firstChannel = 0;
	mix_rate = GLOBAL_DEF("audio/mix_rate",44100);

	int latency = GLOBAL_DEF("audio/output_latency",25);
	unsigned int buffer_size = nearest_power_of_2( latency * mix_rate / 1000 );
	if (OS::get_singleton()->is_stdout_verbose()) {
		print_line("audio buffer size: "+itos(buffer_size));
	}

//	bool success=false;

	while( true) {

		switch(output_format) {

			case OUTPUT_MONO: parameters.nChannels = 1; break;
			case OUTPUT_STEREO: parameters.nChannels = 2; break;
			case OUTPUT_QUAD: parameters.nChannels = 4; break;
			case OUTPUT_5_1: parameters.nChannels = 6; break;
		};

		try {
			dac->openStream( &parameters, NULL, RTAUDIO_SINT32,
			    mix_rate, &buffer_size, &callback, this,&options );
			mutex = Mutex::create(true);
			active=true;

			break;
        } catch ( RtAudioError& e ) {
			// try with less channels

			ERR_PRINT("Unable to open audio, retrying with fewer channels..");

			switch(output_format) {

				case OUTPUT_MONO: ERR_EXPLAIN("Unable to open audio."); ERR_FAIL_V( ERR_UNAVAILABLE ); break;
				case OUTPUT_STEREO: output_format=OUTPUT_MONO; break;
				case OUTPUT_QUAD: output_format=OUTPUT_STEREO; break;
				case OUTPUT_5_1: output_format=OUTPUT_QUAD; break;
			};
		}
	}

	return OK;
}

int AudioDriverRtAudio::get_mix_rate() const {

	return mix_rate;
}

AudioDriverSW::OutputFormat AudioDriverRtAudio::get_output_format() const {

	return output_format;
}

void AudioDriverRtAudio::start() {

	if (active)
		dac->startStream();
}

void AudioDriverRtAudio::lock() {

	if (mutex)
		mutex->lock();
}

void AudioDriverRtAudio::unlock() {

	if (mutex)
		mutex->unlock();
}

void AudioDriverRtAudio::finish() {

	 if ( active && dac->isStreamOpen() )
		 dac->closeStream();
	 if (mutex)
		 memdelete(mutex);
	 if (dac)
		 memdelete(dac);
}

AudioDriverRtAudio::AudioDriverRtAudio()
{
	mutex=NULL;
	mix_rate=44100;
	output_format=OUTPUT_STEREO;
}

#endif
<commit_msg>RtAudio: proper under/overflow warning<commit_after>/*************************************************/
/*  audio_driver_rtaudio.cpp                     */
/*************************************************/
/*            This file is part of:              */
/*                GODOT ENGINE                   */
/*************************************************/
/*       Source code within this file is:        */
/*  (c) 2007-2016 Juan Linietsky, Ariel Manzur   */
/*             All Rights Reserved.              */
/*************************************************/

#include "audio_driver_rtaudio.h"
#include "globals.h"
#include "os/os.h"
#ifdef RTAUDIO_ENABLED

const char* AudioDriverRtAudio::get_name() const {

#ifdef OSX_ENABLED
	return "RtAudio-OSX";
#elif defined(UNIX_ENABLED)
	return "RtAudio-ALSA";
#elif defined(WINDOWS_ENABLED)
	return "RtAudio-DirectSound";
#else
	return "RtAudio-None";
#endif

}

// Two-channel sawtooth wave generator.
int AudioDriverRtAudio::callback( void *outputBuffer, void *inputBuffer, unsigned int nBufferFrames,
	double streamTime, RtAudioStreamStatus status, void *userData ) {

	if (status) {
		if (status & RTAUDIO_INPUT_OVERFLOW) {
			WARN_PRINT("RtAudio input overflow!");
		}
		if (status & RTAUDIO_OUTPUT_UNDERFLOW) {
			WARN_PRINT("RtAudio output underflow!");
		}
	}
	int32_t *buffer = (int32_t *) outputBuffer;

	AudioDriverRtAudio *self = (AudioDriverRtAudio*)userData;

	if (self->mutex->try_lock()!=OK) {

		// what should i do..
		for(unsigned int i=0;i<nBufferFrames;i++)
			buffer[i]=0;

		return 0;
	}

	self->audio_server_process(nBufferFrames,buffer);

	self->mutex->unlock();;

	return 0;
}

Error AudioDriverRtAudio::init() {

	active=false;
	mutex=NULL;
	dac = memnew( RtAudio );

	ERR_EXPLAIN("Cannot initialize RtAudio audio driver: No devices present.")
	ERR_FAIL_COND_V( dac->getDeviceCount() < 1, ERR_UNAVAILABLE );

	String channels = GLOBAL_DEF("audio/output","stereo");

	if (channels=="5.1")
		output_format=OUTPUT_5_1;
	else if (channels=="quad")
		output_format=OUTPUT_QUAD;
	else if (channels=="mono")
		output_format=OUTPUT_MONO;
	else
		output_format=OUTPUT_STEREO;

	RtAudio::StreamParameters parameters;
	parameters.deviceId = dac->getDefaultOutputDevice();
	RtAudio::StreamOptions options;
//	options.
//	RtAudioStreamFlags flags;      /*!< A bit-mask of stream flags (RTAUDIO_NONINTERLEAVED, RTAUDIO_MINIMIZE_LATENCY, RTAUDIO_HOG_DEVICE). *///
//	unsigned int numberOfBuffers;  /*!< Number of stream buffers. */
//	std::string streamName;        /*!< A stream name (currently used only in Jack). */
//	int priority;                  /*!< Scheduling priority of callback thread (only used with flag RTAUDIO_SCHEDULE_REALTIME). */

	parameters.firstChannel = 0;
	mix_rate = GLOBAL_DEF("audio/mix_rate",44100);

	int latency = GLOBAL_DEF("audio/output_latency",25);
	unsigned int buffer_size = nearest_power_of_2( latency * mix_rate / 1000 );
	if (OS::get_singleton()->is_stdout_verbose()) {
		print_line("audio buffer size: "+itos(buffer_size));
	}

//	bool success=false;

	while( true) {

		switch(output_format) {

			case OUTPUT_MONO: parameters.nChannels = 1; break;
			case OUTPUT_STEREO: parameters.nChannels = 2; break;
			case OUTPUT_QUAD: parameters.nChannels = 4; break;
			case OUTPUT_5_1: parameters.nChannels = 6; break;
		};

		try {
			dac->openStream( &parameters, NULL, RTAUDIO_SINT32,
			    mix_rate, &buffer_size, &callback, this,&options );
			mutex = Mutex::create(true);
			active=true;

			break;
        } catch ( RtAudioError& e ) {
			// try with less channels

			ERR_PRINT("Unable to open audio, retrying with fewer channels..");

			switch(output_format) {

				case OUTPUT_MONO: ERR_EXPLAIN("Unable to open audio."); ERR_FAIL_V( ERR_UNAVAILABLE ); break;
				case OUTPUT_STEREO: output_format=OUTPUT_MONO; break;
				case OUTPUT_QUAD: output_format=OUTPUT_STEREO; break;
				case OUTPUT_5_1: output_format=OUTPUT_QUAD; break;
			};
		}
	}

	return OK;
}

int AudioDriverRtAudio::get_mix_rate() const {

	return mix_rate;
}

AudioDriverSW::OutputFormat AudioDriverRtAudio::get_output_format() const {

	return output_format;
}

void AudioDriverRtAudio::start() {

	if (active)
		dac->startStream();
}

void AudioDriverRtAudio::lock() {

	if (mutex)
		mutex->lock();
}

void AudioDriverRtAudio::unlock() {

	if (mutex)
		mutex->unlock();
}

void AudioDriverRtAudio::finish() {

	 if ( active && dac->isStreamOpen() )
		 dac->closeStream();
	 if (mutex)
		 memdelete(mutex);
	 if (dac)
		 memdelete(dac);
}

AudioDriverRtAudio::AudioDriverRtAudio()
{
	mutex=NULL;
	mix_rate=44100;
	output_format=OUTPUT_STEREO;
}

#endif
<|endoftext|>


<commit_before>// This file is part of the dune-gdt project:
//   http://users.dune-project.org/projects/dune-gdt
// Copyright holders: Felix Schindler
// License: BSD 2-Clause License (http://opensource.org/licenses/BSD-2-Clause)

#ifndef DUNE_GDT_PLAYGROUND_SPACES_FV_DEFAULT_HH
#define DUNE_GDT_PLAYGROUND_SPACES_FV_DEFAULT_HH

#include <dune/common/deprecated.hh>

#include <dune/stuff/common/type_utils.hh>

#include <dune/gdt/spaces/parallel.hh>

#include "../../mapper/finitevolume.hh"
#include <dune/gdt/basefunctionset/default/fv.hh>
#include "../../../spaces/interface.hh"

namespace Dune {
namespace GDT {
namespace Spaces {
namespace FV {

// forward, to be used in the traits and to allow for specialization
template <class GridViewImp, class RangeFieldImp, int rangeDim, int rangeDimCols = 1>
class Default
{
  static_assert(Dune::AlwaysFalse<GridViewImp>::value, "Untested for these dimensions!");
};

/**
 *  \brief Traits class for Spaces::CG::FemBased.
 */
template <class GridViewImp, class RangeFieldImp, int rangeDim, int rangeDimCols>
class DefaultTraits
{
public:
  typedef Default<GridViewImp, RangeFieldImp, rangeDim, rangeDimCols> derived_type;
  static const int polOrder = 0;
  typedef GridViewImp GridViewType;
  typedef typename GridViewType::IndexSet BackendType;
  typedef typename GridViewType::template Codim<0>::Entity EntityType;
  typedef RangeFieldImp RangeFieldType;
  typedef Mapper::FiniteVolume<GridViewType, rangeDim, rangeDimCols> MapperType;
  typedef BaseFunctionSet::FiniteVolume<typename GridViewType::template Codim<0>::Entity, typename GridViewType::ctype,
                                        GridViewType::dimension, RangeFieldType, rangeDim,
                                        rangeDimCols> BaseFunctionSetType;
  static const Stuff::Grid::ChoosePartView part_view_type = Stuff::Grid::ChoosePartView::view;
  static const bool needs_grid_view                       = true;
  typedef CommunicationChooser<GridViewType> CommunicationChooserType;
  typedef typename CommunicationChooserType::Type CommunicatorType;
}; // class DefaultTraits

template <class GridViewImp, class RangeFieldImp, int rangeDim>
class Default<GridViewImp, RangeFieldImp, rangeDim, 1>
    : public SpaceInterface<DefaultTraits<GridViewImp, RangeFieldImp, rangeDim, 1>, GridViewImp::dimension, rangeDim, 1>
{
  typedef Default<GridViewImp, RangeFieldImp, rangeDim, 1> ThisType;
  typedef SpaceInterface<DefaultTraits<GridViewImp, RangeFieldImp, rangeDim, 1>, GridViewImp::dimension, rangeDim, 1>
      BaseType;

public:
  typedef DefaultTraits<GridViewImp, RangeFieldImp, rangeDim, 1> Traits;

  static const int polOrder              = Traits::polOrder;
  static const unsigned int dimDomain    = BaseType::dimDomain;
  static const unsigned int dimRange     = BaseType::dimRange;
  static const unsigned int dimRangeCols = BaseType::dimRangeCols;

  typedef typename Traits::GridViewType GridViewType;
  typedef typename Traits::RangeFieldType RangeFieldType;
  typedef typename Traits::BackendType BackendType;
  typedef typename Traits::MapperType MapperType;
  typedef typename Traits::EntityType EntityType;
  typedef typename Traits::BaseFunctionSetType BaseFunctionSetType;
  typedef typename Traits::CommunicationChooserType CommunicationChooserType;
  typedef typename Traits::CommunicatorType CommunicatorType;

  typedef Dune::Stuff::LA::SparsityPatternDefault PatternType;
  typedef typename GridViewType::ctype DomainFieldType;

  Default(GridViewType gv)
    : grid_view_(gv)
    , mapper_(grid_view_)
    , communicator_(CommunicationChooserType::create(grid_view_))
  {
  }

  Default(const ThisType& other)
    : grid_view_(other.grid_view_)
    , mapper_(other.mapper_)
    , communicator_(CommunicationChooserType::create(grid_view_))
  {
  }

  Default(ThisType&& source) = default;

  ThisType& operator=(const ThisType& other) = delete;

  ThisType& operator=(ThisType&& source) = delete;

  const GridViewType& grid_view() const
  {
    return grid_view_;
  }

  const BackendType& backend() const
  {
    return grid_view_.indexSet();
  }

  const MapperType& mapper() const
  {
    return mapper_;
  }

  BaseFunctionSetType base_function_set(const EntityType& entity) const
  {
    return BaseFunctionSetType(entity);
  }

  using BaseType::compute_pattern;

  template <class G, class S, int d, int r, int rC>
  PatternType compute_pattern(const GridView<G>& local_grid_view, const SpaceInterface<S, d, r, rC>& ansatz_space) const
  {
    return BaseType::compute_face_and_volume_pattern(local_grid_view, ansatz_space);
  }

  CommunicatorType& communicator() const
  {
    // no need to prepare the communicator, since we are not pdelab based
    return *communicator_;
  }

private:
  const GridViewType grid_view_;
  const MapperType mapper_;
  const std::unique_ptr<CommunicatorType> communicator_;
}; // class Default< ..., 1, 1 >

} // namespace FV
} // namespace Spaces
} // namespace GDT
} // namespace Dune

#endif // DUNE_GDT_PLAYGROUND_SPACES_FV_DEFAULT_HH
<commit_msg>[spaces.fv.default] update include, refs #15<commit_after>// This file is part of the dune-gdt project:
//   http://users.dune-project.org/projects/dune-gdt
// Copyright holders: Felix Schindler
// License: BSD 2-Clause License (http://opensource.org/licenses/BSD-2-Clause)

#ifndef DUNE_GDT_PLAYGROUND_SPACES_FV_DEFAULT_HH
#define DUNE_GDT_PLAYGROUND_SPACES_FV_DEFAULT_HH

#include <dune/common/deprecated.hh>

#include <dune/stuff/common/type_utils.hh>

#include <dune/gdt/spaces/parallel.hh>

#include <dune/gdt/basefunctionset/default/fv.hh>
#include <dune/gdt/mapper/default/fv.hh>
#include "../../../spaces/interface.hh"

namespace Dune {
namespace GDT {
namespace Spaces {
namespace FV {

// forward, to be used in the traits and to allow for specialization
template <class GridViewImp, class RangeFieldImp, int rangeDim, int rangeDimCols = 1>
class Default
{
  static_assert(Dune::AlwaysFalse<GridViewImp>::value, "Untested for these dimensions!");
};

/**
 *  \brief Traits class for Spaces::CG::FemBased.
 */
template <class GridViewImp, class RangeFieldImp, int rangeDim, int rangeDimCols>
class DefaultTraits
{
public:
  typedef Default<GridViewImp, RangeFieldImp, rangeDim, rangeDimCols> derived_type;
  static const int polOrder = 0;
  typedef GridViewImp GridViewType;
  typedef typename GridViewType::IndexSet BackendType;
  typedef typename GridViewType::template Codim<0>::Entity EntityType;
  typedef RangeFieldImp RangeFieldType;
  typedef Mapper::FiniteVolume<GridViewType, rangeDim, rangeDimCols> MapperType;
  typedef BaseFunctionSet::FiniteVolume<typename GridViewType::template Codim<0>::Entity, typename GridViewType::ctype,
                                        GridViewType::dimension, RangeFieldType, rangeDim,
                                        rangeDimCols> BaseFunctionSetType;
  static const Stuff::Grid::ChoosePartView part_view_type = Stuff::Grid::ChoosePartView::view;
  static const bool needs_grid_view                       = true;
  typedef CommunicationChooser<GridViewType> CommunicationChooserType;
  typedef typename CommunicationChooserType::Type CommunicatorType;
}; // class DefaultTraits

template <class GridViewImp, class RangeFieldImp, int rangeDim>
class Default<GridViewImp, RangeFieldImp, rangeDim, 1>
    : public SpaceInterface<DefaultTraits<GridViewImp, RangeFieldImp, rangeDim, 1>, GridViewImp::dimension, rangeDim, 1>
{
  typedef Default<GridViewImp, RangeFieldImp, rangeDim, 1> ThisType;
  typedef SpaceInterface<DefaultTraits<GridViewImp, RangeFieldImp, rangeDim, 1>, GridViewImp::dimension, rangeDim, 1>
      BaseType;

public:
  typedef DefaultTraits<GridViewImp, RangeFieldImp, rangeDim, 1> Traits;

  static const int polOrder              = Traits::polOrder;
  static const unsigned int dimDomain    = BaseType::dimDomain;
  static const unsigned int dimRange     = BaseType::dimRange;
  static const unsigned int dimRangeCols = BaseType::dimRangeCols;

  typedef typename Traits::GridViewType GridViewType;
  typedef typename Traits::RangeFieldType RangeFieldType;
  typedef typename Traits::BackendType BackendType;
  typedef typename Traits::MapperType MapperType;
  typedef typename Traits::EntityType EntityType;
  typedef typename Traits::BaseFunctionSetType BaseFunctionSetType;
  typedef typename Traits::CommunicationChooserType CommunicationChooserType;
  typedef typename Traits::CommunicatorType CommunicatorType;

  typedef Dune::Stuff::LA::SparsityPatternDefault PatternType;
  typedef typename GridViewType::ctype DomainFieldType;

  Default(GridViewType gv)
    : grid_view_(gv)
    , mapper_(grid_view_)
    , communicator_(CommunicationChooserType::create(grid_view_))
  {
  }

  Default(const ThisType& other)
    : grid_view_(other.grid_view_)
    , mapper_(other.mapper_)
    , communicator_(CommunicationChooserType::create(grid_view_))
  {
  }

  Default(ThisType&& source) = default;

  ThisType& operator=(const ThisType& other) = delete;

  ThisType& operator=(ThisType&& source) = delete;

  const GridViewType& grid_view() const
  {
    return grid_view_;
  }

  const BackendType& backend() const
  {
    return grid_view_.indexSet();
  }

  const MapperType& mapper() const
  {
    return mapper_;
  }

  BaseFunctionSetType base_function_set(const EntityType& entity) const
  {
    return BaseFunctionSetType(entity);
  }

  using BaseType::compute_pattern;

  template <class G, class S, int d, int r, int rC>
  PatternType compute_pattern(const GridView<G>& local_grid_view, const SpaceInterface<S, d, r, rC>& ansatz_space) const
  {
    return BaseType::compute_face_and_volume_pattern(local_grid_view, ansatz_space);
  }

  CommunicatorType& communicator() const
  {
    // no need to prepare the communicator, since we are not pdelab based
    return *communicator_;
  }

private:
  const GridViewType grid_view_;
  const MapperType mapper_;
  const std::unique_ptr<CommunicatorType> communicator_;
}; // class Default< ..., 1, 1 >

} // namespace FV
} // namespace Spaces
} // namespace GDT
} // namespace Dune

#endif // DUNE_GDT_PLAYGROUND_SPACES_FV_DEFAULT_HH
<|endoftext|>


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

  Program:   Visualization Toolkit
  Module:    vtkGarbageCollector.cxx

  Copyright (c) Ken Martin, Will Schroeder, Bill Lorensen
  All rights reserved.
  See Copyright.txt or http://www.kitware.com/Copyright.htm 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 notice for more information.

=========================================================================*/
#include "vtkGarbageCollector.h"

#include <vtkstd/map>
#include <vtkstd/queue>
#include <vtkstd/stack>
#include <vtkstd/vector>

vtkCxxRevisionMacro(vtkGarbageCollector, "1.8");

//----------------------------------------------------------------------------
class vtkGarbageCollectorInternals
{
public:
  struct Entry;

  // Map from each object to its garbage collection entry.
  typedef vtkstd::map<vtkObjectBase*, Entry> EntriesType;
  struct Entry
  {
    Entry(): Root(), InComponent(0), VisitOrder(0), Queued(0), References() {}

    // The candidate root for the component containing this object.
    EntriesType::iterator Root;

    // Mark whether the object has been assigned to a component.
    int InComponent;

    // Mark the order in which object's are visited by Tarjan's algorithm.
    int VisitOrder;

    // Whether this entry has been queued while computing net reference count.
    int Queued;

    // The list of references reported by this entry's object.
    typedef vtkstd::vector<EntriesType::iterator> ReferencesType;
    ReferencesType References;
  };

  // The main garbage collector instance.
  vtkGarbageCollector* External;

  // The set of objects that have been visited during the DFS.
  EntriesType Entries;

  // The stack of objects forming the connected components.
  typedef vtkstd::stack<EntriesType::iterator> StackType;
  StackType Stack;

  // The object currently being explored.
  EntriesType::iterator Current;

  // Count for visit order.
  int Count;

  // The objects in the root's connected component.
  typedef vtkstd::vector<vtkObjectBase*> ComponentType;
  ComponentType Component;

  // Find the strongly connected components reachable from the given root.
  EntriesType::iterator FindStrongComponents(vtkObjectBase*);

  // Callback from objects to report references.
  void ReportReference(vtkObjectBase*);

  // Node visitor for Tarjan's algorithm.
  EntriesType::iterator VisitTarjan(vtkObjectBase*);

  // Find/Print/Delete the set of objects in the root's strongly
  // connected component.
  int FindComponent(EntriesType::iterator);
  void PrintComponent(ostream& os);
  void DeleteComponent();
};

//----------------------------------------------------------------------------
vtkGarbageCollector::vtkGarbageCollector(vtkGarbageCollectorInternals* internal)
{
  this->Internal = internal;
  this->Internal->External = this;
  this->Internal->Current = this->Internal->Entries.end();
}

//----------------------------------------------------------------------------
vtkGarbageCollector::~vtkGarbageCollector()
{
  this->SetReferenceCount(0);
}

//----------------------------------------------------------------------------
void vtkGarbageCollector::PrintSelf(ostream& os, vtkIndent indent)
{
  this->Superclass::PrintSelf(os, indent);
}

//----------------------------------------------------------------------------
void vtkGarbageCollector::Register(vtkObjectBase*)
{
}

//----------------------------------------------------------------------------
void vtkGarbageCollector::UnRegister(vtkObjectBase*)
{
}

//----------------------------------------------------------------------------
void vtkGarbageCollector::Check(vtkObjectBase* root)
{
  // Allocate as much as possible on the runtime stack.  This code
  // runs every time UnRegister is called on an object supporting
  // garbage collection.  It may be worth modifying the stack and map
  // to use a local array for storage until the size grows beyond some
  // constant.
  vtkGarbageCollectorInternals internal;
  vtkGarbageCollector collector(&internal);

  // Uncomment these lines to get reference loop debugging for objects
  // with Debug flag set:
  //if(vtkObject* obj = vtkObject::SafeDownCast(root))
  //  {
  //  collector.SetDebug(obj->GetDebug());
  //  }

  collector.SetDebug(1);

  // Do collection if necessary.
  collector.CheckReferenceLoops(root);

  // Avoid destruction message.
  collector.SetDebug(0);
}

//----------------------------------------------------------------------------
#ifdef VTK_LEAN_AND_MEAN
void vtkGarbageCollector::ReportReference(vtkObjectBase* obj, const char*)
{
  // Forward call to the internal implementation.
  if(obj)
    {
    this->Internal->ReportReference(obj);
    }
}
#else
void vtkGarbageCollector::ReportReference(vtkObjectBase* obj, const char* desc)
{
  if(obj)
    {
    // Report debugging information if requested.
    if(this->Debug && vtkObject::GetGlobalWarningDisplay())
      {
      vtkObjectBase* current = this->Internal->Current->first;
      ostrstream msg;
      msg << "ReportReference: "
          << current->GetClassName() << "(" << current << ") "
          << (desc?desc:"")
          << " -> " << obj->GetClassName() << "(" << obj << ")";
      msg << ends;
      vtkDebugMacro(<< msg.str());
      msg.rdbuf()->freeze(0);
      }

    // Forward call to the internal implementation.
    this->Internal->ReportReference(obj);
    }
}
#endif

//----------------------------------------------------------------------------
void vtkGarbageCollector::ReportReferences(vtkObjectBase* obj)
{
#ifndef VTK_LEAN_AND_MEAN
  // Report debugging information if requested.
  if(this->Debug && vtkObject::GetGlobalWarningDisplay())
    {
    vtkObjectBase* current = this->Internal->Current->first;
    vtkDebugMacro("Requesting references from "
                  << current->GetClassName() << "("
                  << current << ") with reference count "
                  << current->GetReferenceCount());
    }
#endif
  obj->ReportReferences(this);
}

//----------------------------------------------------------------------------
void vtkGarbageCollector::RemoveReferences(vtkObjectBase* obj)
{
  obj->RemoveReferences();
}

//----------------------------------------------------------------------------
void vtkGarbageCollector::GarbageCollectionStarting(vtkObjectBase* obj)
{
  obj->GarbageCollectionStarting();
}

//----------------------------------------------------------------------------
void vtkGarbageCollector::GarbageCollectionFinishing(vtkObjectBase* obj)
{
  obj->GarbageCollectionFinishing();
}

//----------------------------------------------------------------------------
void vtkGarbageCollector::CheckReferenceLoops(vtkObjectBase* root)
{
  // This traverses the reference graph associated with the given root
  // object.  If the total reference count of the strongly connected
  // component is 0 when not counting internal references, the entire
  // component is deleted.

  vtkDebugMacro("Starting reference graph walk with root "
                << root->GetClassName() << "(" << root << ")");

  // Find the strongly connected components reachable from this root.
  vtkGarbageCollectorInternals::EntriesType::iterator
    rootEntry = this->Internal->FindStrongComponents(root);

  vtkDebugMacro("Finished reference graph walk with root "
                << root->GetClassName() << "(" << root << ")");

  // Find the net reference count of the component containing the root.
  int netCount = this->Internal->FindComponent(rootEntry);

#ifndef VTK_LEAN_AND_MEAN
  if(this->Debug && vtkObject::GetGlobalWarningDisplay())
    {
    ostrstream msg;
    msg << "Identified strongly connected component with net reference count "
        << netCount << ":";
    this->Internal->PrintComponent(msg);
    msg << ends;
    vtkDebugMacro(<< msg.str());
    msg.rdbuf()->freeze(0);
    }
#endif

  // If the net reference count is zero, delete the component.
  if(netCount == 0)
    {
    vtkDebugMacro("Deleting strongly connected component of reference graph.");
    this->Internal->DeleteComponent();
    }
}

//----------------------------------------------------------------------------
int vtkGarbageCollectorInternals::FindComponent(EntriesType::iterator root)
{
  // The queue of objects while checking the net reference count.
  typedef vtkstd::queue<EntriesType::iterator> QueueType;
  QueueType entryQueue;

  // Initialize the queue with the root object.
  int netCount = root->first->GetReferenceCount();
  this->Component.push_back(root->first);
  root->second.Queued = 1;
  entryQueue.push(root);

  // Loop until the queue is empty.
  while(!entryQueue.empty())
    {
    // Get the next object from the queue.
    EntriesType::iterator v = entryQueue.front();
    entryQueue.pop();

    // Process the references to objects in the component.
    for(Entry::ReferencesType::iterator r = v->second.References.begin();
        r != v->second.References.end(); ++r)
      {
      EntriesType::iterator w = *r;
      if(w->second.Root == root)
        {
        if(!w->second.Queued)
          {
          // Include the references to this object.
          netCount += w->first->GetReferenceCount();

          // Add the object to the list of objects in the component.
          this->Component.push_back(w->first);

          // Queue the object.
          w->second.Queued = 1;
          entryQueue.push(w);
          }

        // This is an internal reference, so decrement the net count.
        --netCount;
        }
      }
    }

  return netCount;
}

//----------------------------------------------------------------------------
vtkGarbageCollectorInternals::EntriesType::iterator
vtkGarbageCollectorInternals::FindStrongComponents(vtkObjectBase* root)
{
  // Use Tarjan's algorithm to visit the reference graph and mark
  // strongly connected components.
  this->Count = 0;
  return this->VisitTarjan(root);
}

//----------------------------------------------------------------------------
void vtkGarbageCollectorInternals::ReportReference(vtkObjectBase* obj)
{
  // Get the source and destination of this reference.
  EntriesType::iterator v = this->Current;
  EntriesType::iterator w = this->Entries.find(obj);

  // Visit the destination of this reference if it has not been visited.
  if(w == this->Entries.end())
    {
    w = this->VisitTarjan(obj);
    }

  // If the destination has not yet been assigned to a component,
  // check if it is a better potential root for the current object.
  if(!w->second.InComponent)
    {
    if(w->second.Root->second.VisitOrder < v->second.Root->second.VisitOrder)
      {
      v->second.Root = w->second.Root;
      }
    }

  // Save this reference.
  v->second.References.push_back(w);
}

//----------------------------------------------------------------------------
vtkGarbageCollectorInternals::EntriesType::iterator
vtkGarbageCollectorInternals::VisitTarjan(vtkObjectBase* obj)
{
  // Create an entry for the object.
  EntriesType::value_type entry(obj, Entry());
  EntriesType::iterator v = this->Entries.insert(entry).first;

  // Initialize the entry and push it onto the stack of graph nodes.
  v->second.Root = v;
  v->second.InComponent = 0;
  v->second.VisitOrder = ++this->Count;
  this->Stack.push(v);

  // Process the references from this node.
  EntriesType::iterator saveCurrent = this->Current;
  this->Current = v;
  this->External->ReportReferences(v->first);
  this->Current = saveCurrent;

  // If we have found a component mark its members.
  if(v->second.Root == v)
    {
    EntriesType::iterator w;
    do
      {
      w = this->Stack.top();
      this->Stack.pop();
      w->second.InComponent = 1;
      w->second.Root = v;
      } while(w != v);
    }

  return v;
}

//----------------------------------------------------------------------------
void vtkGarbageCollectorInternals::PrintComponent(ostream& os)
{
  for(ComponentType::iterator i = this->Component.begin();
      i != this->Component.end(); ++i)
    {
    os << "\n  " << (*i)->GetClassName() << "(" << *i << ")";
    }
}

//----------------------------------------------------------------------------
void vtkGarbageCollectorInternals::DeleteComponent()
{
  ComponentType::iterator obj;

  // Notify all objects they are about to be garbage collected.
  // They will disable reference loop checking.
  for(obj = this->Component.begin(); obj != this->Component.end(); ++obj)
    {
    vtkGarbageCollector::GarbageCollectionStarting(*obj);
    }

  // Disconnect the reference graph.
  for(obj = this->Component.begin(); obj != this->Component.end(); ++obj)
    {
    vtkGarbageCollector::RemoveReferences(*obj);
    }

  // Notify all objects they have been garbage collected.  They will
  // delete themselves.
  for(obj = this->Component.begin(); obj != this->Component.end(); ++obj)
    {
    vtkGarbageCollector::GarbageCollectionFinishing(*obj);
    }
}
<commit_msg>BUG: Removed force enabling of debug mode.<commit_after>/*=========================================================================

  Program:   Visualization Toolkit
  Module:    vtkGarbageCollector.cxx

  Copyright (c) Ken Martin, Will Schroeder, Bill Lorensen
  All rights reserved.
  See Copyright.txt or http://www.kitware.com/Copyright.htm 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 notice for more information.

=========================================================================*/
#include "vtkGarbageCollector.h"

#include <vtkstd/map>
#include <vtkstd/queue>
#include <vtkstd/stack>
#include <vtkstd/vector>

vtkCxxRevisionMacro(vtkGarbageCollector, "1.9");

//----------------------------------------------------------------------------
class vtkGarbageCollectorInternals
{
public:
  struct Entry;

  // Map from each object to its garbage collection entry.
  typedef vtkstd::map<vtkObjectBase*, Entry> EntriesType;
  struct Entry
  {
    Entry(): Root(), InComponent(0), VisitOrder(0), Queued(0), References() {}

    // The candidate root for the component containing this object.
    EntriesType::iterator Root;

    // Mark whether the object has been assigned to a component.
    int InComponent;

    // Mark the order in which object's are visited by Tarjan's algorithm.
    int VisitOrder;

    // Whether this entry has been queued while computing net reference count.
    int Queued;

    // The list of references reported by this entry's object.
    typedef vtkstd::vector<EntriesType::iterator> ReferencesType;
    ReferencesType References;
  };

  // The main garbage collector instance.
  vtkGarbageCollector* External;

  // The set of objects that have been visited during the DFS.
  EntriesType Entries;

  // The stack of objects forming the connected components.
  typedef vtkstd::stack<EntriesType::iterator> StackType;
  StackType Stack;

  // The object currently being explored.
  EntriesType::iterator Current;

  // Count for visit order.
  int Count;

  // The objects in the root's connected component.
  typedef vtkstd::vector<vtkObjectBase*> ComponentType;
  ComponentType Component;

  // Find the strongly connected components reachable from the given root.
  EntriesType::iterator FindStrongComponents(vtkObjectBase*);

  // Callback from objects to report references.
  void ReportReference(vtkObjectBase*);

  // Node visitor for Tarjan's algorithm.
  EntriesType::iterator VisitTarjan(vtkObjectBase*);

  // Find/Print/Delete the set of objects in the root's strongly
  // connected component.
  int FindComponent(EntriesType::iterator);
  void PrintComponent(ostream& os);
  void DeleteComponent();
};

//----------------------------------------------------------------------------
vtkGarbageCollector::vtkGarbageCollector(vtkGarbageCollectorInternals* internal)
{
  this->Internal = internal;
  this->Internal->External = this;
  this->Internal->Current = this->Internal->Entries.end();
}

//----------------------------------------------------------------------------
vtkGarbageCollector::~vtkGarbageCollector()
{
  this->SetReferenceCount(0);
}

//----------------------------------------------------------------------------
void vtkGarbageCollector::PrintSelf(ostream& os, vtkIndent indent)
{
  this->Superclass::PrintSelf(os, indent);
}

//----------------------------------------------------------------------------
void vtkGarbageCollector::Register(vtkObjectBase*)
{
}

//----------------------------------------------------------------------------
void vtkGarbageCollector::UnRegister(vtkObjectBase*)
{
}

//----------------------------------------------------------------------------
void vtkGarbageCollector::Check(vtkObjectBase* root)
{
  // Allocate as much as possible on the runtime stack.  This code
  // runs every time UnRegister is called on an object supporting
  // garbage collection.  It may be worth modifying the stack and map
  // to use a local array for storage until the size grows beyond some
  // constant.
  vtkGarbageCollectorInternals internal;
  vtkGarbageCollector collector(&internal);

  // Uncomment these lines to get reference loop debugging for objects
  // with Debug flag set:
  //if(vtkObject* obj = vtkObject::SafeDownCast(root))
  //  {
  //  collector.SetDebug(obj->GetDebug());
  //  }

  // Do collection if necessary.
  collector.CheckReferenceLoops(root);

  // Avoid destruction message.
  collector.SetDebug(0);
}

//----------------------------------------------------------------------------
#ifdef VTK_LEAN_AND_MEAN
void vtkGarbageCollector::ReportReference(vtkObjectBase* obj, const char*)
{
  // Forward call to the internal implementation.
  if(obj)
    {
    this->Internal->ReportReference(obj);
    }
}
#else
void vtkGarbageCollector::ReportReference(vtkObjectBase* obj, const char* desc)
{
  if(obj)
    {
    // Report debugging information if requested.
    if(this->Debug && vtkObject::GetGlobalWarningDisplay())
      {
      vtkObjectBase* current = this->Internal->Current->first;
      ostrstream msg;
      msg << "ReportReference: "
          << current->GetClassName() << "(" << current << ") "
          << (desc?desc:"")
          << " -> " << obj->GetClassName() << "(" << obj << ")";
      msg << ends;
      vtkDebugMacro(<< msg.str());
      msg.rdbuf()->freeze(0);
      }

    // Forward call to the internal implementation.
    this->Internal->ReportReference(obj);
    }
}
#endif

//----------------------------------------------------------------------------
void vtkGarbageCollector::ReportReferences(vtkObjectBase* obj)
{
#ifndef VTK_LEAN_AND_MEAN
  // Report debugging information if requested.
  if(this->Debug && vtkObject::GetGlobalWarningDisplay())
    {
    vtkObjectBase* current = this->Internal->Current->first;
    vtkDebugMacro("Requesting references from "
                  << current->GetClassName() << "("
                  << current << ") with reference count "
                  << current->GetReferenceCount());
    }
#endif
  obj->ReportReferences(this);
}

//----------------------------------------------------------------------------
void vtkGarbageCollector::RemoveReferences(vtkObjectBase* obj)
{
  obj->RemoveReferences();
}

//----------------------------------------------------------------------------
void vtkGarbageCollector::GarbageCollectionStarting(vtkObjectBase* obj)
{
  obj->GarbageCollectionStarting();
}

//----------------------------------------------------------------------------
void vtkGarbageCollector::GarbageCollectionFinishing(vtkObjectBase* obj)
{
  obj->GarbageCollectionFinishing();
}

//----------------------------------------------------------------------------
void vtkGarbageCollector::CheckReferenceLoops(vtkObjectBase* root)
{
  // This traverses the reference graph associated with the given root
  // object.  If the total reference count of the strongly connected
  // component is 0 when not counting internal references, the entire
  // component is deleted.

  vtkDebugMacro("Starting reference graph walk with root "
                << root->GetClassName() << "(" << root << ")");

  // Find the strongly connected components reachable from this root.
  vtkGarbageCollectorInternals::EntriesType::iterator
    rootEntry = this->Internal->FindStrongComponents(root);

  vtkDebugMacro("Finished reference graph walk with root "
                << root->GetClassName() << "(" << root << ")");

  // Find the net reference count of the component containing the root.
  int netCount = this->Internal->FindComponent(rootEntry);

#ifndef VTK_LEAN_AND_MEAN
  if(this->Debug && vtkObject::GetGlobalWarningDisplay())
    {
    ostrstream msg;
    msg << "Identified strongly connected component with net reference count "
        << netCount << ":";
    this->Internal->PrintComponent(msg);
    msg << ends;
    vtkDebugMacro(<< msg.str());
    msg.rdbuf()->freeze(0);
    }
#endif

  // If the net reference count is zero, delete the component.
  if(netCount == 0)
    {
    vtkDebugMacro("Deleting strongly connected component of reference graph.");
    this->Internal->DeleteComponent();
    }
}

//----------------------------------------------------------------------------
int vtkGarbageCollectorInternals::FindComponent(EntriesType::iterator root)
{
  // The queue of objects while checking the net reference count.
  typedef vtkstd::queue<EntriesType::iterator> QueueType;
  QueueType entryQueue;

  // Initialize the queue with the root object.
  int netCount = root->first->GetReferenceCount();
  this->Component.push_back(root->first);
  root->second.Queued = 1;
  entryQueue.push(root);

  // Loop until the queue is empty.
  while(!entryQueue.empty())
    {
    // Get the next object from the queue.
    EntriesType::iterator v = entryQueue.front();
    entryQueue.pop();

    // Process the references to objects in the component.
    for(Entry::ReferencesType::iterator r = v->second.References.begin();
        r != v->second.References.end(); ++r)
      {
      EntriesType::iterator w = *r;
      if(w->second.Root == root)
        {
        if(!w->second.Queued)
          {
          // Include the references to this object.
          netCount += w->first->GetReferenceCount();

          // Add the object to the list of objects in the component.
          this->Component.push_back(w->first);

          // Queue the object.
          w->second.Queued = 1;
          entryQueue.push(w);
          }

        // This is an internal reference, so decrement the net count.
        --netCount;
        }
      }
    }

  return netCount;
}

//----------------------------------------------------------------------------
vtkGarbageCollectorInternals::EntriesType::iterator
vtkGarbageCollectorInternals::FindStrongComponents(vtkObjectBase* root)
{
  // Use Tarjan's algorithm to visit the reference graph and mark
  // strongly connected components.
  this->Count = 0;
  return this->VisitTarjan(root);
}

//----------------------------------------------------------------------------
void vtkGarbageCollectorInternals::ReportReference(vtkObjectBase* obj)
{
  // Get the source and destination of this reference.
  EntriesType::iterator v = this->Current;
  EntriesType::iterator w = this->Entries.find(obj);

  // Visit the destination of this reference if it has not been visited.
  if(w == this->Entries.end())
    {
    w = this->VisitTarjan(obj);
    }

  // If the destination has not yet been assigned to a component,
  // check if it is a better potential root for the current object.
  if(!w->second.InComponent)
    {
    if(w->second.Root->second.VisitOrder < v->second.Root->second.VisitOrder)
      {
      v->second.Root = w->second.Root;
      }
    }

  // Save this reference.
  v->second.References.push_back(w);
}

//----------------------------------------------------------------------------
vtkGarbageCollectorInternals::EntriesType::iterator
vtkGarbageCollectorInternals::VisitTarjan(vtkObjectBase* obj)
{
  // Create an entry for the object.
  EntriesType::value_type entry(obj, Entry());
  EntriesType::iterator v = this->Entries.insert(entry).first;

  // Initialize the entry and push it onto the stack of graph nodes.
  v->second.Root = v;
  v->second.InComponent = 0;
  v->second.VisitOrder = ++this->Count;
  this->Stack.push(v);

  // Process the references from this node.
  EntriesType::iterator saveCurrent = this->Current;
  this->Current = v;
  this->External->ReportReferences(v->first);
  this->Current = saveCurrent;

  // If we have found a component mark its members.
  if(v->second.Root == v)
    {
    EntriesType::iterator w;
    do
      {
      w = this->Stack.top();
      this->Stack.pop();
      w->second.InComponent = 1;
      w->second.Root = v;
      } while(w != v);
    }

  return v;
}

//----------------------------------------------------------------------------
void vtkGarbageCollectorInternals::PrintComponent(ostream& os)
{
  for(ComponentType::iterator i = this->Component.begin();
      i != this->Component.end(); ++i)
    {
    os << "\n  " << (*i)->GetClassName() << "(" << *i << ")";
    }
}

//----------------------------------------------------------------------------
void vtkGarbageCollectorInternals::DeleteComponent()
{
  ComponentType::iterator obj;

  // Notify all objects they are about to be garbage collected.
  // They will disable reference loop checking.
  for(obj = this->Component.begin(); obj != this->Component.end(); ++obj)
    {
    vtkGarbageCollector::GarbageCollectionStarting(*obj);
    }

  // Disconnect the reference graph.
  for(obj = this->Component.begin(); obj != this->Component.end(); ++obj)
    {
    vtkGarbageCollector::RemoveReferences(*obj);
    }

  // Notify all objects they have been garbage collected.  They will
  // delete themselves.
  for(obj = this->Component.begin(); obj != this->Component.end(); ++obj)
    {
    vtkGarbageCollector::GarbageCollectionFinishing(*obj);
    }
}
<|endoftext|>


<commit_before>//
//  AY-3-8910.cpp
//  Clock Signal
//
//  Created by Thomas Harte on 14/10/2016.
//  Copyright © 2016 Thomas Harte. All rights reserved.
//

#include "AY38910.hpp"

using namespace GI;

AY38910::AY38910() :
	_selected_register(0),
	_channel_output{0, 0, 0}, _channel_dividers{0, 0, 0}, _tone_generator_controls{0, 0, 0},
	_noise_shift_register(0xffff), _noise_divider(0), _noise_output(0),
	_envelope_divider(0), _envelope_period(0), _envelope_position(0),
	_output_registers{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
{
	_output_registers[8] = _output_registers[9] = _output_registers[10] = 0;

	// set up envelope lookup tables
	for(int c = 0; c < 16; c++)
	{
		for(int p = 0; p < 32; p++)
		{
			switch(c)
			{
				case 0: case 1: case 2: case 3: case 9:
					_envelope_shapes[c][p] = (p < 16) ? (p^0xf) : 0;
					_envelope_overflow_masks[c] = 0x1f;
				break;
				case 4: case 5: case 6: case 7: case 15:
					_envelope_shapes[c][p] = (p < 16) ? p : 0;
					_envelope_overflow_masks[c] = 0x1f;
				break;

				case 8:
					_envelope_shapes[c][p] = (p & 0xf) ^ 0xf;
					_envelope_overflow_masks[c] = 0x00;
				break;
				case 12:
					_envelope_shapes[c][p] = (p & 0xf);
					_envelope_overflow_masks[c] = 0x00;
				break;

				case 10:
					_envelope_shapes[c][p] = (p & 0xf) ^ ((p < 16) ? 0xf : 0x0);
					_envelope_overflow_masks[c] = 0x00;
				break;
				case 14:
					_envelope_shapes[c][p] = (p & 0xf) ^ ((p < 16) ? 0x0 : 0xf);
					_envelope_overflow_masks[c] = 0x00;
				break;

				case 11:
					_envelope_shapes[c][p] = (p < 16) ? (p^0xf) : 0xf;
					_envelope_overflow_masks[c] = 0x1f;
				break;
				case 13:
					_envelope_shapes[c][p] = (p < 16) ? p : 0xf;
					_envelope_overflow_masks[c] = 0x1f;
				break;
			}
		}
	}

	// set up volume lookup table
	float max_volume = 8192;
	float root_two = sqrtf(2.0f);
	for(int v = 0; v < 16; v++)
	{
		_volumes[v] = (int)(max_volume / powf(root_two, (float)(v ^ 0xf)));
	}
	_volumes[0] = 0;
}

void AY38910::set_clock_rate(double clock_rate)
{
	set_input_rate((float)clock_rate);
}

void AY38910::get_samples(unsigned int number_of_samples, int16_t *target)
{
	int offset = _master_divider;
	int c = _master_divider;
	_master_divider += number_of_samples;

	for(; c < 16 && c < _master_divider; c++) target[c - offset] = _output_volume;
	while(c < _master_divider)
	{
#define step_channel(c)	\
	if(_channel_dividers[c]) _channel_dividers[c] --;	\
	else { _channel_dividers[c] = _tone_generator_controls[c]; _channel_output[c] ^= 1; }

		// update the tone channels
		step_channel(0);
		step_channel(1);
		step_channel(2);

#undef step_channel

		// ... the noise generator. This recomputes the new bit repeatedly but harmlessly, only shifting
		// it into the official 17 upon divider underflow.
		if(_noise_divider) _noise_divider--;
		else
		{
			_noise_divider = _output_registers[6];
			_noise_output ^= _noise_shift_register&1;
			_noise_shift_register |= ((_noise_shift_register ^ (_noise_shift_register >> 3))&1) << 17;
			_noise_shift_register >>= 1;
		}

		// ... and the envelope generator. Table based for pattern lookup, with a 'refill' step — a way of
		// implementing non-repeating patterns by locking them to table position 0x1f.
		if(_envelope_divider) _envelope_divider--;
		else
		{
			_envelope_divider = _envelope_period;
			_envelope_position ++;
			if(_envelope_position == 32) _envelope_position = _envelope_overflow_masks[_output_registers[13]];
		}

		evaluate_output_volume();

		for(int ic = 0; ic < 16 && c < _master_divider; ic++)
		{
			target[c - offset] = _output_volume;
			c++;
		}
	}
}

void AY38910::evaluate_output_volume()
{
	int envelope_volume = _envelope_shapes[_output_registers[13]][_envelope_position];

	// The output level for a channel is:
	//	1 if neither tone nor noise is enabled;
	//	0 if either tone or noise is enabled and its value is low.
	// (which is implemented here with reverse logic, assuming _channel_output and _noise_output are already inverted)
#define level(c, tb, nb)	\
	(((((_output_registers[7] >> tb)&1)^1) & _channel_output[c]) | ((((_output_registers[7] >> nb)&1)^1) & _noise_output)) ^ 1

	int channel_levels[3] = {
		level(0, 0, 3),
		level(1, 1, 4),
		level(2, 2, 5),
	};
#undef level

		// Channel volume is a simple selection: if the bit at 0x10 is set, use the envelope volume; otherwise use the lower four bits
#define channel_volume(c)	\
	((_output_registers[c] >> 4)&1) * envelope_volume + (((_output_registers[c] >> 4)&1)^1) * (_output_registers[c]&0xf)

	int volumes[3] = {
		channel_volume(8),
		channel_volume(9),
		channel_volume(10)
	};
#undef channel_volume

	// Mix additively.
	_output_volume = (int16_t)(
		_volumes[volumes[0]] * channel_levels[0] +
		_volumes[volumes[1]] * channel_levels[1] +
		_volumes[volumes[2]] * channel_levels[2]
	);
}

void AY38910::skip_samples(unsigned int number_of_samples)
{
	// TODO
//	printf("Skip %d\n", number_of_samples);
}

void AY38910::select_register(uint8_t r)
{
	_selected_register = r & 0xf;
}

void AY38910::set_register_value(uint8_t value)
{
	_registers[_selected_register] = value;
	if(_selected_register < 14)
	{
		int selected_register = _selected_register;
		enqueue([=] () {
			uint8_t masked_value = value;
			switch(selected_register)
			{
				case 0: case 2: case 4:
					_tone_generator_controls[selected_register >> 1] =
						(_tone_generator_controls[selected_register >> 1] & ~0xff) | value;
					_channel_dividers[selected_register >> 1] = _tone_generator_controls[selected_register >> 1];
				break;

				case 1: case 3: case 5:
					_tone_generator_controls[selected_register >> 1] =
						(_tone_generator_controls[selected_register >> 1] & 0xff) | (uint16_t)((value&0xf) << 8);
					_channel_dividers[selected_register >> 1] = _tone_generator_controls[selected_register >> 1];
				break;

				case 6:
					masked_value &= 0x1f;
					_noise_divider = masked_value;
				break;

				case 11:
					_envelope_period = (_envelope_period & ~0xff) | value;
					_envelope_divider = _envelope_period;
				break;

				case 12:
					_envelope_period = (_envelope_period & 0xff) | (int)(value << 8);
					_envelope_divider = _envelope_period;
				break;

				case 13:
					masked_value &= 0xf;
					_envelope_position = 0;
				break;
			}
			_output_registers[selected_register] = masked_value;
			evaluate_output_volume();
		});
	}
}

uint8_t AY38910::get_register_value()
{
	return _registers[_selected_register];
}

uint8_t AY38910::get_port_output(bool port_b)
{
	return _registers[port_b ? 15 : 14];
}

void AY38910::set_data_input(uint8_t r)
{
	_data_input = r;
}

uint8_t AY38910::get_data_output()
{
	return _data_output;
}

void AY38910::set_control_lines(ControlLines control_lines)
{
	ControlState new_state;
	switch((int)control_lines)
	{
		default:					new_state = Inactive;		break;

		case (int)(BCDIR | BC2 | BC1):
		case BCDIR:
		case BC1:					new_state = LatchAddress;	break;

		case (int)(BC2 | BC1):		new_state = Read;			break;
		case (int)(BCDIR | BC2):	new_state = Write;			break;
	}

	if(new_state != _control_state)
	{
		_control_state = new_state;
		switch(new_state)
		{
			default: break;
			case LatchAddress:	select_register(_data_input);			break;
			case Write:			set_register_value(_data_input);		break;
			case Read:			_data_output = get_register_value();	break;
		}
	}
}
<commit_msg>Slightly simplified code, fixed divider.<commit_after>//
//  AY-3-8910.cpp
//  Clock Signal
//
//  Created by Thomas Harte on 14/10/2016.
//  Copyright © 2016 Thomas Harte. All rights reserved.
//

#include "AY38910.hpp"

using namespace GI;

AY38910::AY38910() :
	_selected_register(0),
	_channel_output{0, 0, 0}, _channel_dividers{0, 0, 0}, _tone_generator_controls{0, 0, 0},
	_noise_shift_register(0xffff), _noise_divider(0), _noise_output(0),
	_envelope_divider(0), _envelope_period(0), _envelope_position(0),
	_output_registers{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
{
	_output_registers[8] = _output_registers[9] = _output_registers[10] = 0;

	// set up envelope lookup tables
	for(int c = 0; c < 16; c++)
	{
		for(int p = 0; p < 32; p++)
		{
			switch(c)
			{
				case 0: case 1: case 2: case 3: case 9:
					_envelope_shapes[c][p] = (p < 16) ? (p^0xf) : 0;
					_envelope_overflow_masks[c] = 0x1f;
				break;
				case 4: case 5: case 6: case 7: case 15:
					_envelope_shapes[c][p] = (p < 16) ? p : 0;
					_envelope_overflow_masks[c] = 0x1f;
				break;

				case 8:
					_envelope_shapes[c][p] = (p & 0xf) ^ 0xf;
					_envelope_overflow_masks[c] = 0x00;
				break;
				case 12:
					_envelope_shapes[c][p] = (p & 0xf);
					_envelope_overflow_masks[c] = 0x00;
				break;

				case 10:
					_envelope_shapes[c][p] = (p & 0xf) ^ ((p < 16) ? 0xf : 0x0);
					_envelope_overflow_masks[c] = 0x00;
				break;
				case 14:
					_envelope_shapes[c][p] = (p & 0xf) ^ ((p < 16) ? 0x0 : 0xf);
					_envelope_overflow_masks[c] = 0x00;
				break;

				case 11:
					_envelope_shapes[c][p] = (p < 16) ? (p^0xf) : 0xf;
					_envelope_overflow_masks[c] = 0x1f;
				break;
				case 13:
					_envelope_shapes[c][p] = (p < 16) ? p : 0xf;
					_envelope_overflow_masks[c] = 0x1f;
				break;
			}
		}
	}

	// set up volume lookup table
	float max_volume = 8192;
	float root_two = sqrtf(2.0f);
	for(int v = 0; v < 16; v++)
	{
		_volumes[v] = (int)(max_volume / powf(root_two, (float)(v ^ 0xf)));
	}
	_volumes[0] = 0;
}

void AY38910::set_clock_rate(double clock_rate)
{
	set_input_rate((float)clock_rate);
}

void AY38910::get_samples(unsigned int number_of_samples, int16_t *target)
{
	int offset = _master_divider;
	int c = _master_divider;
	_master_divider += number_of_samples;

	for(; c < 16 && c < _master_divider; c++) target[c - offset] = _output_volume;
	while(c < _master_divider)
	{
#define step_channel(c)	\
	if(_channel_dividers[c]) _channel_dividers[c] --;	\
	else { _channel_dividers[c] = _tone_generator_controls[c]; _channel_output[c] ^= 1; }

		// update the tone channels
		step_channel(0);
		step_channel(1);
		step_channel(2);

#undef step_channel

		// ... the noise generator. This recomputes the new bit repeatedly but harmlessly, only shifting
		// it into the official 17 upon divider underflow.
		if(_noise_divider) _noise_divider--;
		else
		{
			_noise_divider = _output_registers[6];
			_noise_output ^= _noise_shift_register&1;
			_noise_shift_register |= ((_noise_shift_register ^ (_noise_shift_register >> 3))&1) << 17;
			_noise_shift_register >>= 1;
		}

		// ... and the envelope generator. Table based for pattern lookup, with a 'refill' step — a way of
		// implementing non-repeating patterns by locking them to table position 0x1f.
		if(_envelope_divider) _envelope_divider--;
		else
		{
			_envelope_divider = _envelope_period;
			_envelope_position ++;
			if(_envelope_position == 32) _envelope_position = _envelope_overflow_masks[_output_registers[13]];
		}

		evaluate_output_volume();

		for(int ic = 0; ic < 16 && c < _master_divider; ic++)
		{
			target[c - offset] = _output_volume;
			c++;
		}
	}

	_master_divider &= 15;
}

void AY38910::evaluate_output_volume()
{
	int envelope_volume = _envelope_shapes[_output_registers[13]][_envelope_position];

	// The output level for a channel is:
	//	1 if neither tone nor noise is enabled;
	//	0 if either tone or noise is enabled and its value is low.
	// (which is implemented here with reverse logic, assuming _channel_output and _noise_output are already inverted)
#define level(c, tb, nb)	\
	(((((_output_registers[7] >> tb)&1)^1) & _channel_output[c]) | ((((_output_registers[7] >> nb)&1)^1) & _noise_output)) ^ 1

	int channel_levels[3] = {
		level(0, 0, 3),
		level(1, 1, 4),
		level(2, 2, 5),
	};
#undef level

		// Channel volume is a simple selection: if the bit at 0x10 is set, use the envelope volume; otherwise use the lower four bits
#define channel_volume(c)	\
	((_output_registers[c] >> 4)&1) * envelope_volume + (((_output_registers[c] >> 4)&1)^1) * (_output_registers[c]&0xf)

	int volumes[3] = {
		channel_volume(8),
		channel_volume(9),
		channel_volume(10)
	};
#undef channel_volume

	// Mix additively.
	_output_volume = (int16_t)(
		_volumes[volumes[0]] * channel_levels[0] +
		_volumes[volumes[1]] * channel_levels[1] +
		_volumes[volumes[2]] * channel_levels[2]
	);
}

void AY38910::skip_samples(unsigned int number_of_samples)
{
	// TODO
//	printf("Skip %d\n", number_of_samples);
}

void AY38910::select_register(uint8_t r)
{
	_selected_register = r & 0xf;
}

void AY38910::set_register_value(uint8_t value)
{
	_registers[_selected_register] = value;
	if(_selected_register < 14)
	{
		int selected_register = _selected_register;
		enqueue([=] () {
			uint8_t masked_value = value;
			switch(selected_register)
			{
				case 0: case 2: case 4:
				case 1: case 3: case 5:
				{
					int channel = selected_register >> 1;
					if(selected_register & 1)
						_tone_generator_controls[channel] = (_tone_generator_controls[channel] & 0xff) | (uint16_t)((value&0xf) << 8);
					else
						_tone_generator_controls[channel] = (_tone_generator_controls[channel] & ~0xff) | value;
					_channel_dividers[channel] = _tone_generator_controls[channel];
				}
				break;

				case 6:
					masked_value &= 0x1f;
					_noise_divider = masked_value;
				break;

				case 11:
					_envelope_period = (_envelope_period & ~0xff) | value;
					_envelope_divider = _envelope_period;
				break;

				case 12:
					_envelope_period = (_envelope_period & 0xff) | (int)(value << 8);
					_envelope_divider = _envelope_period;
				break;

				case 13:
					masked_value &= 0xf;
					_envelope_position = 0;
				break;
			}
			_output_registers[selected_register] = masked_value;
			evaluate_output_volume();
		});
	}
}

uint8_t AY38910::get_register_value()
{
	return _registers[_selected_register];
}

uint8_t AY38910::get_port_output(bool port_b)
{
	return _registers[port_b ? 15 : 14];
}

void AY38910::set_data_input(uint8_t r)
{
	_data_input = r;
}

uint8_t AY38910::get_data_output()
{
	return _data_output;
}

void AY38910::set_control_lines(ControlLines control_lines)
{
	ControlState new_state;
	switch((int)control_lines)
	{
		default:					new_state = Inactive;		break;

		case (int)(BCDIR | BC2 | BC1):
		case BCDIR:
		case BC1:					new_state = LatchAddress;	break;

		case (int)(BC2 | BC1):		new_state = Read;			break;
		case (int)(BCDIR | BC2):	new_state = Write;			break;
	}

	if(new_state != _control_state)
	{
		_control_state = new_state;
		switch(new_state)
		{
			default: break;
			case LatchAddress:	select_register(_data_input);			break;
			case Write:			set_register_value(_data_input);		break;
			case Read:			_data_output = get_register_value();	break;
		}
	}
}
<|endoftext|>


<commit_before>// Copyright (c) 2010-2020, Lawrence Livermore National Security, LLC. Produced
// at the Lawrence Livermore National Laboratory. All Rights reserved. See files
// LICENSE and NOTICE for details. LLNL-CODE-806117.
//
// This file is part of the MFEM library. For more information and source code
// availability visit https://mfem.org.
//
// MFEM is free software; you can redistribute it and/or modify it under the
// terms of the BSD-3 license. We welcome feedback and contributions, see file
// CONTRIBUTING.md for details.

#include "catch.hpp"
#include "mfem.hpp"
#include <fstream>
#include <iostream>

using namespace mfem;

#ifdef MFEM_USE_MPI

namespace sparse_matrix_test
{

double coeff_function(const Vector &x)
{
   return 1.0 + x[0]*x[0];
}

void velocity_function(const Vector &x, Vector &v)
{
   int dim = x.Size();
   switch (dim)
   {
      case 1: v(0) = 1.0; break;
      case 2: v(0) = x(1); v(1) = -x(0); break;
      case 3: v(0) = x(1); v(1) = -x(0); v(2) = x(0); break;
   }
}

static std::string getString(AssemblyLevel assembly)
{
   switch (assembly)
   {
      case AssemblyLevel::NONE:
         return "NONE";
         break;
      case AssemblyLevel::PARTIAL:
         return "PARTIAL";
         break;
      case AssemblyLevel::ELEMENT:
         return "ELEMENT";
         break;
      case AssemblyLevel::FULL:
         return "FULL";
         break;
      case AssemblyLevel::LEGACYFULL:
         return "LEGACYFULL";
         break;
   }
   mfem_error("Unknown AssemblyLevel.");
   return "";
}

enum class Coeff {Const, Grid, Quad};

static std::string getString(Coeff coeff_type)
{
   switch (coeff_type)
   {
      case Coeff::Const:
         return "Const";
         break;
      case Coeff::Grid:
         return "Grid";
         break;
      case Coeff::Quad:
         return "Quad";
         break;
   }
   mfem_error("Unknown CeedCoeff.");
   return "";
}

enum class Problem {Mass, Convection, Diffusion};

static std::string getString(Problem pb)
{
   switch (pb)
   {
      case Problem::Mass:
         return "Mass";
         break;
      case Problem::Convection:
         return "Convection";
         break;
      case Problem::Diffusion:
         return "Diffusion";
         break;
   }
   mfem_error("Unknown Problem.");
   return "";
}

void test_sparse_matrix(const char* input, int order, const Coeff coeff_type,
                        const Problem pb, const AssemblyLevel assembly)
{
   std::string section = "assembly: " + getString(assembly) + "\n" +
                         "coeff_type: " + getString(coeff_type) + "\n" +
                         "pb: " + getString(pb) + "\n" +
                         "order: " + std::to_string(order) + "\n" +
                         "mesh: " + input;
   INFO(section);
   Mesh mesh(input, 1, 1);
   mesh.EnsureNodes();
   mesh.UniformRefinement();
   ParMesh pmesh(MPI_COMM_WORLD, mesh);
   int dim = mesh.Dimension();

   FiniteElementCollection *fec;
   if (pb == Problem::Convection)
   {
      fec = new L2_FECollection(order, dim, BasisType::GaussLobatto);
   }
   else
   {
      fec = new H1_FECollection(order, dim);
   }
   ParFiniteElementSpace fes(&pmesh, fec);

   ParBilinearForm k_test(&fes);
   ParBilinearForm k_ref(&fes);

   ParFiniteElementSpace coeff_fes(&pmesh, fec);
   ParGridFunction gf(&coeff_fes);

   Coefficient *coeff = nullptr;
   ConstantCoefficient rho(1.0);
   VectorFunctionCoefficient velocity(dim, velocity_function);
   switch (coeff_type)
   {
      case Coeff::Const:
         coeff = new ConstantCoefficient(1.0);
         break;
      case Coeff::Grid:
      {
         FunctionCoefficient f_coeff(coeff_function);
         gf.ProjectCoefficient(f_coeff);
         coeff = new GridFunctionCoefficient(&gf);
         break;
      }
      case Coeff::Quad:
         coeff = new FunctionCoefficient(coeff_function);
         break;
   }

   switch (pb)
   {
      case Problem::Mass:
         k_ref.AddDomainIntegrator(new MassIntegrator(*coeff));
         k_test.AddDomainIntegrator(new MassIntegrator(*coeff));
         break;
      case Problem::Convection:
         k_ref.AddDomainIntegrator(new ConvectionIntegrator(velocity, -1.0));
         k_ref.AddInteriorFaceIntegrator(
            new TransposeIntegrator(new DGTraceIntegrator(rho, velocity, 1.0, -0.5)));
         k_ref.AddBdrFaceIntegrator(
            new TransposeIntegrator(new DGTraceIntegrator(rho, velocity, 1.0, -0.5)));
         k_test.AddDomainIntegrator(new ConvectionIntegrator(velocity, -1.0));
         k_test.AddInteriorFaceIntegrator(
            new TransposeIntegrator(new DGTraceIntegrator(rho, velocity, 1.0, -0.5)));
         k_test.AddBdrFaceIntegrator(
            new TransposeIntegrator(new DGTraceIntegrator(rho, velocity, 1.0, -0.5)));
         break;
      case Problem::Diffusion:
         k_ref.AddDomainIntegrator(new DiffusionIntegrator(*coeff));
         k_test.AddDomainIntegrator(new DiffusionIntegrator(*coeff));
         break;
   }

   k_ref.Assemble();
   k_ref.Finalize();
   k_ref.KeepNbrBlock();

   k_test.SetAssemblyLevel(assembly);
   k_test.Assemble();

   const int sizeIn  = pb == Problem::Convection ?
                       fes.GetVSize() + fes.GetFaceNbrVSize() :
                       fes.GetVSize();
   const int sizeOut = fes.GetVSize();
   Vector x(sizeIn), y_test(sizeOut), y_ref(sizeOut);
   x.Randomize(1);

   k_test.SpMat().Mult(x,y_test);
   k_ref.Mult(x,y_ref);

   y_test -= y_ref;

   REQUIRE(y_test.Norml2() < 1.e-12);
   delete coeff;
   delete fec;
}

TEST_CASE("Sparse Matrix", "[Parallel]")
{
   auto assembly = GENERATE(AssemblyLevel::PARTIAL,AssemblyLevel::ELEMENT);
   auto coeff_type = GENERATE(Coeff::Const,Coeff::Grid,Coeff::Quad);
   auto pb = GENERATE(Problem::Mass,Problem::Convection,Problem::Diffusion);
   auto order = GENERATE(1,2,3);
   auto mesh = GENERATE("../../data/inline-quad.mesh","../../data/inline-hex.mesh",
                        "../../data/star-q2.mesh","../../data/fichera-q2.mesh");
   test_sparse_matrix(mesh, order, coeff_type, pb, assembly);
} // test case

} // namespace sparse_matrix_test

#endif // MFEM_USE_MPI
<commit_msg>Try something<commit_after>// Copyright (c) 2010-2020, Lawrence Livermore National Security, LLC. Produced
// at the Lawrence Livermore National Laboratory. All Rights reserved. See files
// LICENSE and NOTICE for details. LLNL-CODE-806117.
//
// This file is part of the MFEM library. For more information and source code
// availability visit https://mfem.org.
//
// MFEM is free software; you can redistribute it and/or modify it under the
// terms of the BSD-3 license. We welcome feedback and contributions, see file
// CONTRIBUTING.md for details.

#include "catch.hpp"
#include "mfem.hpp"
#include <fstream>
#include <iostream>

using namespace mfem;

#ifdef MFEM_USE_MPI

namespace sparse_matrix_test
{

double coeff_function(const Vector &x)
{
   return 1.0 + x[0]*x[0];
}

void velocity_function(const Vector &x, Vector &v)
{
   int dim = x.Size();
   switch (dim)
   {
      case 1: v(0) = 1.0; break;
      case 2: v(0) = x(1); v(1) = -x(0); break;
      case 3: v(0) = x(1); v(1) = -x(0); v(2) = x(0); break;
   }
}

static std::string getString(AssemblyLevel assembly)
{
   switch (assembly)
   {
      case AssemblyLevel::NONE:
         return "NONE";
         break;
      case AssemblyLevel::PARTIAL:
         return "PARTIAL";
         break;
      case AssemblyLevel::ELEMENT:
         return "ELEMENT";
         break;
      case AssemblyLevel::FULL:
         return "FULL";
         break;
      case AssemblyLevel::LEGACYFULL:
         return "LEGACYFULL";
         break;
   }
   mfem_error("Unknown AssemblyLevel.");
   return "";
}

enum class Coeff {Const, Grid, Quad};

static std::string getString(Coeff coeff_type)
{
   switch (coeff_type)
   {
      case Coeff::Const:
         return "Const";
         break;
      case Coeff::Grid:
         return "Grid";
         break;
      case Coeff::Quad:
         return "Quad";
         break;
   }
   mfem_error("Unknown CeedCoeff.");
   return "";
}

enum class Problem {Mass, Convection, Diffusion};

static std::string getString(Problem pb)
{
   switch (pb)
   {
      case Problem::Mass:
         return "Mass";
         break;
      case Problem::Convection:
         return "Convection";
         break;
      case Problem::Diffusion:
         return "Diffusion";
         break;
   }
   mfem_error("Unknown Problem.");
   return "";
}

void test_sparse_matrix(const char* input, int order, const Coeff coeff_type,
                        const Problem pb, const AssemblyLevel assembly)
{
   std::string section = "assembly: " + getString(assembly) + "\n" +
                         "coeff_type: " + getString(coeff_type) + "\n" +
                         "pb: " + getString(pb) + "\n" +
                         "order: " + std::to_string(order) + "\n" +
                         "mesh: " + input;
   INFO(section);
   Mesh mesh(input, 1, 1);
   mesh.EnsureNodes();
   mesh.UniformRefinement();
   ParMesh pmesh(MPI_COMM_WORLD, mesh);
   int dim = mesh.Dimension();

   FiniteElementCollection *fec;
   if (pb == Problem::Convection)
   {
      fec = new L2_FECollection(order, dim, BasisType::GaussLobatto);
   }
   else
   {
      fec = new H1_FECollection(order, dim);
   }
   ParFiniteElementSpace fes(&pmesh, fec);

   ParBilinearForm k_test(&fes);
   ParBilinearForm k_ref(&fes);

   ParFiniteElementSpace coeff_fes(&pmesh, fec);
   ParGridFunction gf(&coeff_fes);

   Coefficient *coeff = nullptr;
   ConstantCoefficient rho(1.0);
   VectorFunctionCoefficient velocity(dim, velocity_function);
   switch (coeff_type)
   {
      case Coeff::Const:
         coeff = new ConstantCoefficient(1.0);
         break;
      case Coeff::Grid:
      {
         FunctionCoefficient f_coeff(coeff_function);
         gf.ProjectCoefficient(f_coeff);
         coeff = new GridFunctionCoefficient(&gf);
         break;
      }
      case Coeff::Quad:
         coeff = new FunctionCoefficient(coeff_function);
         break;
   }

   switch (pb)
   {
      case Problem::Mass:
         k_ref.AddDomainIntegrator(new MassIntegrator(*coeff));
         k_test.AddDomainIntegrator(new MassIntegrator(*coeff));
         break;
      case Problem::Convection:
         k_ref.AddDomainIntegrator(new ConvectionIntegrator(velocity, -1.0));
         k_ref.AddInteriorFaceIntegrator(
            new TransposeIntegrator(new DGTraceIntegrator(rho, velocity, 1.0, -0.5)));
         k_ref.AddBdrFaceIntegrator(
            new TransposeIntegrator(new DGTraceIntegrator(rho, velocity, 1.0, -0.5)));
         k_test.AddDomainIntegrator(new ConvectionIntegrator(velocity, -1.0));
         k_test.AddInteriorFaceIntegrator(
            new TransposeIntegrator(new DGTraceIntegrator(rho, velocity, 1.0, -0.5)));
         k_test.AddBdrFaceIntegrator(
            new TransposeIntegrator(new DGTraceIntegrator(rho, velocity, 1.0, -0.5)));
         break;
      case Problem::Diffusion:
         k_ref.AddDomainIntegrator(new DiffusionIntegrator(*coeff));
         k_test.AddDomainIntegrator(new DiffusionIntegrator(*coeff));
         break;
   }

   k_ref.Assemble();
   k_ref.Finalize();
   k_ref.KeepNbrBlock();

   k_test.SetAssemblyLevel(assembly);
   k_test.Assemble();

   const int sizeIn  = pb == Problem::Convection ?
                       fes.GetVSize() + fes.GetFaceNbrVSize() :
                       fes.GetVSize();
   const int sizeOut = fes.GetVSize();
   Vector x(sizeIn), y_test(sizeOut), y_ref(sizeOut);
   x.Randomize(1);

   k_test.SpMat().Mult(x,y_test);
   k_ref.Mult(x,y_ref);

   y_test -= y_ref;

   REQUIRE(y_test.Norml2() < 1.e-12);
   delete coeff;
   delete fec;
}

TEST_CASE("Sparse Matrix", "[Parallel]")
{
   auto assembly = GENERATE(AssemblyLevel::PARTIAL,AssemblyLevel::ELEMENT);
   auto coeff_type = GENERATE(Coeff::Const,Coeff::Grid,Coeff::Quad);
   auto pb = GENERATE(Problem::Mass,Problem::Convection,Problem::Diffusion);
   auto order = GENERATE(1,2,3);
   auto mesh = GENERATE("../../data/inline-quad.mesh","../../data/inline-hex.mesh",
                        "../../data/star-q2.mesh","../../data/fichera.mesh");
   test_sparse_matrix(mesh, order, coeff_type, pb, assembly);
} // test case

} // namespace sparse_matrix_test

#endif // MFEM_USE_MPI
<|endoftext|>


<commit_before>// Copyright 2017 Google LLC
//
// 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 "riegeli/base/object.h"

#include <stdint.h>

#include <utility>

#include "absl/status/status.h"
#include "riegeli/base/base.h"
#include "riegeli/base/status.h"

namespace riegeli {

// Before C++17 if a constexpr static data member is ODR-used, its definition at
// namespace scope is required. Since C++17 these definitions are deprecated:
// http://en.cppreference.com/w/cpp/language/static
#if __cplusplus < 201703
constexpr uintptr_t ObjectState::kHealthy;
constexpr uintptr_t ObjectState::kClosedSuccessfully;
#endif

absl::Status ObjectState::status() const {
  if (status_ptr_ == kHealthy) return absl::OkStatus();
  if (status_ptr_ == kClosedSuccessfully) {
    return absl::FailedPreconditionError("Object closed");
  }
  return reinterpret_cast<const FailedStatus*>(status_ptr_)->status;
}

bool ObjectState::Fail(absl::Status status) {
  RIEGELI_ASSERT(!status.ok())
      << "Failed precondition of ObjectState::Fail(): status not failed";
  if (status_ptr_ == kHealthy || status_ptr_ == kClosedSuccessfully) {
    status_ptr_ = reinterpret_cast<uintptr_t>(new FailedStatus{
        status_ptr_ == kClosedSuccessfully, std::move(status)});
  }
  return false;
}

bool ObjectState::AnnotateStatus(absl::string_view detail) {
  RIEGELI_ASSERT(!not_failed())
      << "Failed precondition of ObjectState::AnnotateStatus(): "
         "ObjectState not failed";
  absl::Status& status = reinterpret_cast<FailedStatus*>(status_ptr_)->status;
  status = Annotate(status, detail);
  return false;
}

void Object::Done() {}

bool Object::Fail(absl::Status status) {
  RIEGELI_ASSERT(!status.ok())
      << "Failed precondition of Object::Fail(): status not failed";
  OnFail();
  state_.Fail(std::move(status));
  DefaultAnnotateStatus();
  return false;
}

bool Object::Fail(const Object& dependency) {
  RIEGELI_ASSERT(!dependency.healthy())
      << "Failed precondition of Object::Fail(): dependency healthy";
  return Fail(dependency.status());
}

void Object::OnFail() {}

void Object::DefaultAnnotateStatus() {
  RIEGELI_ASSERT(!not_failed())
      << "Failed precondition of Object::DefaultAnnotateStatus(): "
         "Object not failed";
}

bool Object::AnnotateStatus(absl::string_view detail) {
  RIEGELI_ASSERT(!not_failed())
      << "Failed precondition of Object::AnnotateStatus(): Object not failed";
  return state_.AnnotateStatus(detail);
}

bool Object::FailWithoutAnnotation(absl::Status status) {
  RIEGELI_ASSERT(!status.ok())
      << "Failed precondition of Object::FailWithoutAnnotation(): "
         "status not failed";
  OnFail();
  state_.Fail(std::move(status));
  return false;
}

bool Object::FailWithoutAnnotation(const Object& dependency) {
  RIEGELI_ASSERT(!dependency.healthy())
      << "Failed precondition of Object::FailWithoutAnnotation(): "
         "dependency healthy";
  return FailWithoutAnnotation(dependency.status());
}

TypeId Object::GetTypeId() const { return TypeId(); }

}  // namespace riegeli
<commit_msg>Fix idempotence of `Fail()`: do not add annotations again.<commit_after>// Copyright 2017 Google LLC
//
// 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 "riegeli/base/object.h"

#include <stdint.h>

#include <utility>

#include "absl/status/status.h"
#include "riegeli/base/base.h"
#include "riegeli/base/status.h"

namespace riegeli {

// Before C++17 if a constexpr static data member is ODR-used, its definition at
// namespace scope is required. Since C++17 these definitions are deprecated:
// http://en.cppreference.com/w/cpp/language/static
#if __cplusplus < 201703
constexpr uintptr_t ObjectState::kHealthy;
constexpr uintptr_t ObjectState::kClosedSuccessfully;
#endif

absl::Status ObjectState::status() const {
  if (status_ptr_ == kHealthy) return absl::OkStatus();
  if (status_ptr_ == kClosedSuccessfully) {
    return absl::FailedPreconditionError("Object closed");
  }
  return reinterpret_cast<const FailedStatus*>(status_ptr_)->status;
}

bool ObjectState::Fail(absl::Status status) {
  RIEGELI_ASSERT(!status.ok())
      << "Failed precondition of ObjectState::Fail(): status not failed";
  if (status_ptr_ == kHealthy || status_ptr_ == kClosedSuccessfully) {
    status_ptr_ = reinterpret_cast<uintptr_t>(new FailedStatus{
        status_ptr_ == kClosedSuccessfully, std::move(status)});
  }
  return false;
}

bool ObjectState::AnnotateStatus(absl::string_view detail) {
  RIEGELI_ASSERT(!not_failed())
      << "Failed precondition of ObjectState::AnnotateStatus(): "
         "ObjectState not failed";
  absl::Status& status = reinterpret_cast<FailedStatus*>(status_ptr_)->status;
  status = Annotate(status, detail);
  return false;
}

void Object::Done() {}

bool Object::Fail(absl::Status status) {
  RIEGELI_ASSERT(!status.ok())
      << "Failed precondition of Object::Fail(): status not failed";
  OnFail();
  if (ABSL_PREDICT_FALSE(!not_failed())) return false;
  state_.Fail(std::move(status));
  DefaultAnnotateStatus();
  return false;
}

bool Object::Fail(const Object& dependency) {
  RIEGELI_ASSERT(!dependency.healthy())
      << "Failed precondition of Object::Fail(): dependency healthy";
  return Fail(dependency.status());
}

void Object::OnFail() {}

void Object::DefaultAnnotateStatus() {
  RIEGELI_ASSERT(!not_failed())
      << "Failed precondition of Object::DefaultAnnotateStatus(): "
         "Object not failed";
}

bool Object::AnnotateStatus(absl::string_view detail) {
  RIEGELI_ASSERT(!not_failed())
      << "Failed precondition of Object::AnnotateStatus(): Object not failed";
  return state_.AnnotateStatus(detail);
}

bool Object::FailWithoutAnnotation(absl::Status status) {
  RIEGELI_ASSERT(!status.ok())
      << "Failed precondition of Object::FailWithoutAnnotation(): "
         "status not failed";
  OnFail();
  if (ABSL_PREDICT_FALSE(!not_failed())) return false;
  state_.Fail(std::move(status));
  return false;
}

bool Object::FailWithoutAnnotation(const Object& dependency) {
  RIEGELI_ASSERT(!dependency.healthy())
      << "Failed precondition of Object::FailWithoutAnnotation(): "
         "dependency healthy";
  return FailWithoutAnnotation(dependency.status());
}

TypeId Object::GetTypeId() const { return TypeId(); }

}  // namespace riegeli
<|endoftext|>


<commit_before><commit_msg>Fixed lattice not quite covering the addressable area<commit_after><|endoftext|>