<commit_before>///////////////////////////////////////////////////////////////////////
// File:        svutil.cpp
// Description: ScrollView Utilities
// Author:      Joern Wanke
// Created:     Thu Nov 29 2007
//
// (C) Copyright 2007, Google Inc.
// 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.
//
///////////////////////////////////////////////////////////////////////
//
// SVUtil contains the SVSync and SVNetwork classes, which are used for
// thread/process creation & synchronization and network connection.

#include <stdio.h>
#ifdef _WIN32
struct addrinfo {
  struct sockaddr* ai_addr;
  int ai_addrlen;
  int ai_family;
  int ai_socktype;
  int ai_protocol;
};
#else
#include <arpa/inet.h>
#include <netinet/in.h>
#include <pthread.h>
#include <semaphore.h>
#include <signal.h>
#include <stdlib.h>
#include <string.h>
#include <netdb.h>
#include <sys/socket.h>
#ifdef __linux__
#include <sys/prctl.h>
#endif
#include <unistd.h>
#endif

#include <cstdlib>
#include <cstring>
#include <iostream>
#include <string>

// Include automatically generated configuration file if running autoconf.
#ifdef HAVE_CONFIG_H
#include "config_auto.h"
#endif

#ifndef GRAPHICS_DISABLED

#include "svutil.h"

const int kBufferSize = 65536;
const int kMaxMsgSize = 4096;

// Signals a thread to exit.
void SVSync::ExitThread() {
#ifdef _WIN32
  // ExitThread(0);
#else
  pthread_exit(0);
#endif
}

// Starts a new process.
void SVSync::StartProcess(const char* executable, const char* args) {
  std::string proc;
  proc.append(executable);
  proc.append(" ");
  proc.append(args);
  std::cout << "Starting " << proc << std::endl;
#ifdef _WIN32
  STARTUPINFO start_info;
  PROCESS_INFORMATION proc_info;
  GetStartupInfo(&start_info);
  if (!CreateProcess(NULL, const_cast<char*>(proc.c_str()), NULL, NULL, FALSE,
                CREATE_NO_WINDOW | DETACHED_PROCESS, NULL, NULL,
                &start_info, &proc_info))
    return;
#else
  int pid = fork();
  if (pid != 0) {   // The father process returns
  } else {
#ifdef __linux__
    // Make sure the java process terminates on exit, since its
    // broken socket detection seems to be useless.
    prctl(PR_SET_PDEATHSIG, 2, 0, 0, 0);
#endif
    char* mutable_args = strdup(args);
    int argc = 1;
    for (int i = 0; mutable_args[i]; ++i) {
      if (mutable_args[i] == ' ') {
        ++argc;
      }
    }
    char** argv = new char*[argc + 2];
    argv[0] = strdup(executable);
    argv[1] = mutable_args;
    argc = 2;
    bool inquote = false;
    for (int i = 0; mutable_args[i]; ++i) {
      if (!inquote && mutable_args[i] == ' ') {
        mutable_args[i] = '\0';
        argv[argc++] = mutable_args + i + 1;
      } else if (mutable_args[i] == '"') {
        inquote = !inquote;
        mutable_args[i] = ' ';
      }
    }
    argv[argc] = NULL;
    execvp(executable, argv);
  }
#endif
}

SVSemaphore::SVSemaphore() {
#ifdef _WIN32
  semaphore_ = CreateSemaphore(0, 0, 10, 0);
#elif defined(__APPLE__)
  char name[50];
  snprintf(name, sizeof(name), "%ld", random());
  sem_unlink(name);
  semaphore_ = sem_open(name, O_CREAT , S_IWUSR, 0);
  if (semaphore_ == SEM_FAILED) {
    perror("sem_open");
  }
#else
  sem_init(&semaphore_, 0, 0);
#endif
}

void SVSemaphore::Signal() {
#ifdef _WIN32
  ReleaseSemaphore(semaphore_, 1, NULL);
#elif defined(__APPLE__)
  sem_post(semaphore_);
#else
  sem_post(&semaphore_);
#endif
}

void SVSemaphore::Wait() {
#ifdef _WIN32
  WaitForSingleObject(semaphore_, INFINITE);
#elif defined(__APPLE__)
  sem_wait(semaphore_);
#else
  sem_wait(&semaphore_);
#endif
}

SVMutex::SVMutex() {
#ifdef _WIN32
  mutex_ = CreateMutex(0, FALSE, 0);
#else
  pthread_mutex_init(&mutex_, NULL);
#endif
}

void SVMutex::Lock() {
#ifdef _WIN32
  WaitForSingleObject(mutex_, INFINITE);
#else
  pthread_mutex_lock(&mutex_);
#endif
}

void SVMutex::Unlock() {
#ifdef _WIN32
  ReleaseMutex(mutex_);
#else
  pthread_mutex_unlock(&mutex_);
#endif
}

// Create new thread.

void SVSync::StartThread(void *(*func)(void*), void* arg) {
#ifdef _WIN32
  LPTHREAD_START_ROUTINE f = (LPTHREAD_START_ROUTINE) func;
  DWORD threadid;
  HANDLE newthread = CreateThread(
  NULL,          // default security attributes
  0,             // use default stack size
  f,             // thread function
  arg,           // argument to thread function
  0,             // use default creation flags
  &threadid);    // returns the thread identifier
#else
  pthread_t helper;
  pthread_create(&helper, NULL, func, arg);
#endif
}

// Place a message in the message buffer (and flush it).
void SVNetwork::Send(const char* msg) {
  mutex_send_->Lock();
  msg_buffer_out_.append(msg);
  mutex_send_->Unlock();
}

// Send the whole buffer.
void SVNetwork::Flush() {
  mutex_send_->Lock();
  while (msg_buffer_out_.size() > 0) {
    int i = send(stream_, msg_buffer_out_.c_str(), msg_buffer_out_.length(), 0);
    msg_buffer_out_.erase(0, i);
  }
  mutex_send_->Unlock();
}

// Receive a message from the server.
// This will always return one line of char* (denoted by \n).
char* SVNetwork::Receive() {
  char* result = NULL;
#if defined(_WIN32) || defined(__CYGWIN__)
  if (has_content) { result = strtok (NULL, "\n"); }
#else
  if (buffer_ptr_ != NULL) { result = strtok_r(NULL, "\n", &buffer_ptr_); }
#endif

  // This means there is something left in the buffer and we return it.
  if (result != NULL) { return result;
  // Otherwise, we read from the stream_.
  } else {
    buffer_ptr_ = NULL;
    has_content = false;

    // The timeout length is not really important since we are looping anyway
    // until a new message is delivered.
    struct timeval tv;
    tv.tv_sec = 10;
    tv.tv_usec = 0;

    // Set the flags to return when the stream_ is ready to be read.
    fd_set readfds;
    FD_ZERO(&readfds);
    FD_SET(stream_, &readfds);

    int i = select(stream_+1, &readfds, NULL, NULL, &tv);

    // The stream_ died.
    if (i == 0) { return NULL; }

    // Read the message buffer.
    i = recv(stream_, msg_buffer_in_, kMaxMsgSize, 0);

    // Server quit (0) or error (-1).
    if (i <= 0) { return NULL; }
    msg_buffer_in_[i] = '\0';
    has_content = true;
#ifdef _WIN32
    return strtok(msg_buffer_in_, "\n");
#else
    // Setup a new string tokenizer.
    return strtok_r(msg_buffer_in_, "\n", &buffer_ptr_);
#endif
  }
}

// Close the connection to the server.
void SVNetwork::Close() {
#ifdef _WIN32
  closesocket(stream_);
#else
  close(stream_);
#endif
}

// The program to invoke to start ScrollView
static const char* ScrollViewProg() {
#ifdef _WIN32
  const char* prog = "java -Xms512m -Xmx1024m";
#else
  const char* prog = "sh";
#endif
  return prog;
}

// The arguments to the program to invoke to start ScrollView
static std::string ScrollViewCommand(std::string scrollview_path) {
  // The following ugly ifdef is to enable the output of the java runtime
  // to be sent down a black hole on non-windows to ignore all the
  // exceptions in piccolo. Ideally piccolo would be debugged to make
  // this unnecessary.
  // Also the path has to be separated by ; on windows and : otherwise.
#ifdef _WIN32
  const char* cmd_template = "-Djava.library.path=%s -jar %s/ScrollView.jar";

#else
  const char* cmd_template = "-c \"trap 'kill %%1' 0 1 2 ; java "
      "-Xms1024m -Xmx2048m -jar %s/ScrollView.jar"
      " & wait\"";
#endif
  int cmdlen = strlen(cmd_template) + 4*strlen(scrollview_path.c_str()) + 1;
  char* cmd = new char[cmdlen];
  const char* sv_path = scrollview_path.c_str();
  snprintf(cmd, cmdlen, cmd_template, sv_path, sv_path, sv_path, sv_path);
  std::string command(cmd);
  delete [] cmd;
  return command;
}

// Platform-independent freeaddrinfo()
static void FreeAddrInfo(struct addrinfo* addr_info) {
  #if defined(__linux__)
  freeaddrinfo(addr_info);
  #else
  delete addr_info->ai_addr;
  delete addr_info;
  #endif
}

// Non-linux version of getaddrinfo()
#if !defined(__linux__)
static int GetAddrInfoNonLinux(const char* hostname, int port,
                               struct addrinfo** addr_info) {
// Get the host data depending on the OS.
  struct sockaddr_in* address;
  *addr_info = new struct addrinfo;
  memset(*addr_info, 0, sizeof(struct addrinfo));
  address = new struct sockaddr_in;
  memset(address, 0, sizeof(struct sockaddr_in));

  (*addr_info)->ai_addr = (struct sockaddr*) address;
  (*addr_info)->ai_addrlen = sizeof(struct sockaddr);
  (*addr_info)->ai_family = AF_INET;
  (*addr_info)->ai_socktype = SOCK_STREAM;

  struct hostent *name;
#ifdef _WIN32
  WSADATA wsaData;
  WSAStartup(MAKEWORD(1, 1), &wsaData);
  name = gethostbyname(hostname);
#else
  name = gethostbyname(hostname);
#endif

  if (name == NULL) {
    FreeAddrInfo(*addr_info);
    *addr_info = NULL;
    return -1;
  }

  // Fill in the appropriate variables to be able to connect to the server.
  address->sin_family = name->h_addrtype;
  memcpy((char *) &address->sin_addr.s_addr,
         name->h_addr_list[0], name->h_length);
  address->sin_port = htons(port);
  return 0;
}
#endif

// Platform independent version of getaddrinfo()
//   Given a hostname:port, produce an addrinfo struct
static int GetAddrInfo(const char* hostname, int port,
                       struct addrinfo** address) {
#if defined(__linux__)
  char port_str[40];
  snprintf(port_str, 40, "%ld", port);
  return getaddrinfo(hostname, port_str, NULL, address);
#else
  return GetAddrInfoNonLinux(hostname, port, address);
#endif
}

// Set up a connection to a ScrollView on hostname:port.
SVNetwork::SVNetwork(const char* hostname, int port) {
  mutex_send_ = new SVMutex();
  msg_buffer_in_ = new char[kMaxMsgSize + 1];
  msg_buffer_in_[0] = '\0';

  has_content = false;
  buffer_ptr_ = NULL;

  struct addrinfo *addr_info = NULL;

  if (GetAddrInfo(hostname, port, &addr_info) != 0) {
    std::cerr << "Error resolving name for ScrollView host "
              << std::string(hostname) << ":" << port << std::endl;
  }

  stream_ = socket(addr_info->ai_family, addr_info->ai_socktype,
                   addr_info->ai_protocol);

  // If server is not there, we will start a new server as local child process.
  if (connect(stream_, addr_info->ai_addr, addr_info->ai_addrlen) < 0) {
    const char* scrollview_path = getenv("SCROLLVIEW_PATH");
    if (scrollview_path == NULL) {
#ifdef SCROLLVIEW_PATH
#define _STR(a) #a
#define _XSTR(a) _STR(a)
      scrollview_path = _XSTR(SCROLLVIEW_PATH);
#undef _XSTR
#undef _STR
#else
      scrollview_path = ".";
#endif
    }
    const char *prog = ScrollViewProg();
    std::string command = ScrollViewCommand(scrollview_path);
    SVSync::StartProcess(prog, command.c_str());

    // Wait for server to show up.
    // Note: There is no exception handling in case the server never turns up.

    stream_ = socket(addr_info->ai_family, addr_info->ai_socktype,
                   addr_info->ai_protocol);

    while (connect(stream_, addr_info->ai_addr,
                   addr_info->ai_addrlen) < 0) {
      std::cout << "ScrollView: Waiting for server...\n";
#ifdef _WIN32
      Sleep(1000);
#else
      sleep(1);
#endif

      stream_ = socket(addr_info->ai_family, addr_info->ai_socktype,
                   addr_info->ai_protocol);
    }
  }
  FreeAddrInfo(addr_info);
}

SVNetwork::~SVNetwork() {
  delete[] msg_buffer_in_;
  delete mutex_send_;
}

#endif  // GRAPHICS_DISABLED
<commit_msg>viewer/svutils.cpp: Include <sys/select.h> for FD_SET, ...<commit_after>///////////////////////////////////////////////////////////////////////
// File:        svutil.cpp
// Description: ScrollView Utilities
// Author:      Joern Wanke
// Created:     Thu Nov 29 2007
//
// (C) Copyright 2007, Google Inc.
// 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.
//
///////////////////////////////////////////////////////////////////////
//
// SVUtil contains the SVSync and SVNetwork classes, which are used for
// thread/process creation & synchronization and network connection.

#include <stdio.h>
#ifdef _WIN32
struct addrinfo {
  struct sockaddr* ai_addr;
  int ai_addrlen;
  int ai_family;
  int ai_socktype;
  int ai_protocol;
};
#else
#include <arpa/inet.h>
#include <netinet/in.h>
#include <pthread.h>
#include <semaphore.h>
#include <signal.h>
#include <stdlib.h>
#include <string.h>
#include <netdb.h>
#include <sys/select.h>
#include <sys/socket.h>
#ifdef __linux__
#include <sys/prctl.h>
#endif
#include <unistd.h>
#endif

#include <cstdlib>
#include <cstring>
#include <iostream>
#include <string>

// Include automatically generated configuration file if running autoconf.
#ifdef HAVE_CONFIG_H
#include "config_auto.h"
#endif

#ifndef GRAPHICS_DISABLED

#include "svutil.h"

const int kBufferSize = 65536;
const int kMaxMsgSize = 4096;

// Signals a thread to exit.
void SVSync::ExitThread() {
#ifdef _WIN32
  // ExitThread(0);
#else
  pthread_exit(0);
#endif
}

// Starts a new process.
void SVSync::StartProcess(const char* executable, const char* args) {
  std::string proc;
  proc.append(executable);
  proc.append(" ");
  proc.append(args);
  std::cout << "Starting " << proc << std::endl;
#ifdef _WIN32
  STARTUPINFO start_info;
  PROCESS_INFORMATION proc_info;
  GetStartupInfo(&start_info);
  if (!CreateProcess(NULL, const_cast<char*>(proc.c_str()), NULL, NULL, FALSE,
                CREATE_NO_WINDOW | DETACHED_PROCESS, NULL, NULL,
                &start_info, &proc_info))
    return;
#else
  int pid = fork();
  if (pid != 0) {   // The father process returns
  } else {
#ifdef __linux__
    // Make sure the java process terminates on exit, since its
    // broken socket detection seems to be useless.
    prctl(PR_SET_PDEATHSIG, 2, 0, 0, 0);
#endif
    char* mutable_args = strdup(args);
    int argc = 1;
    for (int i = 0; mutable_args[i]; ++i) {
      if (mutable_args[i] == ' ') {
        ++argc;
      }
    }
    char** argv = new char*[argc + 2];
    argv[0] = strdup(executable);
    argv[1] = mutable_args;
    argc = 2;
    bool inquote = false;
    for (int i = 0; mutable_args[i]; ++i) {
      if (!inquote && mutable_args[i] == ' ') {
        mutable_args[i] = '\0';
        argv[argc++] = mutable_args + i + 1;
      } else if (mutable_args[i] == '"') {
        inquote = !inquote;
        mutable_args[i] = ' ';
      }
    }
    argv[argc] = NULL;
    execvp(executable, argv);
  }
#endif
}

SVSemaphore::SVSemaphore() {
#ifdef _WIN32
  semaphore_ = CreateSemaphore(0, 0, 10, 0);
#elif defined(__APPLE__)
  char name[50];
  snprintf(name, sizeof(name), "%ld", random());
  sem_unlink(name);
  semaphore_ = sem_open(name, O_CREAT , S_IWUSR, 0);
  if (semaphore_ == SEM_FAILED) {
    perror("sem_open");
  }
#else
  sem_init(&semaphore_, 0, 0);
#endif
}

void SVSemaphore::Signal() {
#ifdef _WIN32
  ReleaseSemaphore(semaphore_, 1, NULL);
#elif defined(__APPLE__)
  sem_post(semaphore_);
#else
  sem_post(&semaphore_);
#endif
}

void SVSemaphore::Wait() {
#ifdef _WIN32
  WaitForSingleObject(semaphore_, INFINITE);
#elif defined(__APPLE__)
  sem_wait(semaphore_);
#else
  sem_wait(&semaphore_);
#endif
}

SVMutex::SVMutex() {
#ifdef _WIN32
  mutex_ = CreateMutex(0, FALSE, 0);
#else
  pthread_mutex_init(&mutex_, NULL);
#endif
}

void SVMutex::Lock() {
#ifdef _WIN32
  WaitForSingleObject(mutex_, INFINITE);
#else
  pthread_mutex_lock(&mutex_);
#endif
}

void SVMutex::Unlock() {
#ifdef _WIN32
  ReleaseMutex(mutex_);
#else
  pthread_mutex_unlock(&mutex_);
#endif
}

// Create new thread.

void SVSync::StartThread(void *(*func)(void*), void* arg) {
#ifdef _WIN32
  LPTHREAD_START_ROUTINE f = (LPTHREAD_START_ROUTINE) func;
  DWORD threadid;
  HANDLE newthread = CreateThread(
  NULL,          // default security attributes
  0,             // use default stack size
  f,             // thread function
  arg,           // argument to thread function
  0,             // use default creation flags
  &threadid);    // returns the thread identifier
#else
  pthread_t helper;
  pthread_create(&helper, NULL, func, arg);
#endif
}

// Place a message in the message buffer (and flush it).
void SVNetwork::Send(const char* msg) {
  mutex_send_->Lock();
  msg_buffer_out_.append(msg);
  mutex_send_->Unlock();
}

// Send the whole buffer.
void SVNetwork::Flush() {
  mutex_send_->Lock();
  while (msg_buffer_out_.size() > 0) {
    int i = send(stream_, msg_buffer_out_.c_str(), msg_buffer_out_.length(), 0);
    msg_buffer_out_.erase(0, i);
  }
  mutex_send_->Unlock();
}

// Receive a message from the server.
// This will always return one line of char* (denoted by \n).
char* SVNetwork::Receive() {
  char* result = NULL;
#if defined(_WIN32) || defined(__CYGWIN__)
  if (has_content) { result = strtok (NULL, "\n"); }
#else
  if (buffer_ptr_ != NULL) { result = strtok_r(NULL, "\n", &buffer_ptr_); }
#endif

  // This means there is something left in the buffer and we return it.
  if (result != NULL) { return result;
  // Otherwise, we read from the stream_.
  } else {
    buffer_ptr_ = NULL;
    has_content = false;

    // The timeout length is not really important since we are looping anyway
    // until a new message is delivered.
    struct timeval tv;
    tv.tv_sec = 10;
    tv.tv_usec = 0;

    // Set the flags to return when the stream_ is ready to be read.
    fd_set readfds;
    FD_ZERO(&readfds);
    FD_SET(stream_, &readfds);

    int i = select(stream_+1, &readfds, NULL, NULL, &tv);

    // The stream_ died.
    if (i == 0) { return NULL; }

    // Read the message buffer.
    i = recv(stream_, msg_buffer_in_, kMaxMsgSize, 0);

    // Server quit (0) or error (-1).
    if (i <= 0) { return NULL; }
    msg_buffer_in_[i] = '\0';
    has_content = true;
#ifdef _WIN32
    return strtok(msg_buffer_in_, "\n");
#else
    // Setup a new string tokenizer.
    return strtok_r(msg_buffer_in_, "\n", &buffer_ptr_);
#endif
  }
}

// Close the connection to the server.
void SVNetwork::Close() {
#ifdef _WIN32
  closesocket(stream_);
#else
  close(stream_);
#endif
}

// The program to invoke to start ScrollView
static const char* ScrollViewProg() {
#ifdef _WIN32
  const char* prog = "java -Xms512m -Xmx1024m";
#else
  const char* prog = "sh";
#endif
  return prog;
}

// The arguments to the program to invoke to start ScrollView
static std::string ScrollViewCommand(std::string scrollview_path) {
  // The following ugly ifdef is to enable the output of the java runtime
  // to be sent down a black hole on non-windows to ignore all the
  // exceptions in piccolo. Ideally piccolo would be debugged to make
  // this unnecessary.
  // Also the path has to be separated by ; on windows and : otherwise.
#ifdef _WIN32
  const char* cmd_template = "-Djava.library.path=%s -jar %s/ScrollView.jar";

#else
  const char* cmd_template = "-c \"trap 'kill %%1' 0 1 2 ; java "
      "-Xms1024m -Xmx2048m -jar %s/ScrollView.jar"
      " & wait\"";
#endif
  int cmdlen = strlen(cmd_template) + 4*strlen(scrollview_path.c_str()) + 1;
  char* cmd = new char[cmdlen];
  const char* sv_path = scrollview_path.c_str();
  snprintf(cmd, cmdlen, cmd_template, sv_path, sv_path, sv_path, sv_path);
  std::string command(cmd);
  delete [] cmd;
  return command;
}

// Platform-independent freeaddrinfo()
static void FreeAddrInfo(struct addrinfo* addr_info) {
  #if defined(__linux__)
  freeaddrinfo(addr_info);
  #else
  delete addr_info->ai_addr;
  delete addr_info;
  #endif
}

// Non-linux version of getaddrinfo()
#if !defined(__linux__)
static int GetAddrInfoNonLinux(const char* hostname, int port,
                               struct addrinfo** addr_info) {
// Get the host data depending on the OS.
  struct sockaddr_in* address;
  *addr_info = new struct addrinfo;
  memset(*addr_info, 0, sizeof(struct addrinfo));
  address = new struct sockaddr_in;
  memset(address, 0, sizeof(struct sockaddr_in));

  (*addr_info)->ai_addr = (struct sockaddr*) address;
  (*addr_info)->ai_addrlen = sizeof(struct sockaddr);
  (*addr_info)->ai_family = AF_INET;
  (*addr_info)->ai_socktype = SOCK_STREAM;

  struct hostent *name;
#ifdef _WIN32
  WSADATA wsaData;
  WSAStartup(MAKEWORD(1, 1), &wsaData);
  name = gethostbyname(hostname);
#else
  name = gethostbyname(hostname);
#endif

  if (name == NULL) {
    FreeAddrInfo(*addr_info);
    *addr_info = NULL;
    return -1;
  }

  // Fill in the appropriate variables to be able to connect to the server.
  address->sin_family = name->h_addrtype;
  memcpy((char *) &address->sin_addr.s_addr,
         name->h_addr_list[0], name->h_length);
  address->sin_port = htons(port);
  return 0;
}
#endif

// Platform independent version of getaddrinfo()
//   Given a hostname:port, produce an addrinfo struct
static int GetAddrInfo(const char* hostname, int port,
                       struct addrinfo** address) {
#if defined(__linux__)
  char port_str[40];
  snprintf(port_str, 40, "%ld", port);
  return getaddrinfo(hostname, port_str, NULL, address);
#else
  return GetAddrInfoNonLinux(hostname, port, address);
#endif
}

// Set up a connection to a ScrollView on hostname:port.
SVNetwork::SVNetwork(const char* hostname, int port) {
  mutex_send_ = new SVMutex();
  msg_buffer_in_ = new char[kMaxMsgSize + 1];
  msg_buffer_in_[0] = '\0';

  has_content = false;
  buffer_ptr_ = NULL;

  struct addrinfo *addr_info = NULL;

  if (GetAddrInfo(hostname, port, &addr_info) != 0) {
    std::cerr << "Error resolving name for ScrollView host "
              << std::string(hostname) << ":" << port << std::endl;
  }

  stream_ = socket(addr_info->ai_family, addr_info->ai_socktype,
                   addr_info->ai_protocol);

  // If server is not there, we will start a new server as local child process.
  if (connect(stream_, addr_info->ai_addr, addr_info->ai_addrlen) < 0) {
    const char* scrollview_path = getenv("SCROLLVIEW_PATH");
    if (scrollview_path == NULL) {
#ifdef SCROLLVIEW_PATH
#define _STR(a) #a
#define _XSTR(a) _STR(a)
      scrollview_path = _XSTR(SCROLLVIEW_PATH);
#undef _XSTR
#undef _STR
#else
      scrollview_path = ".";
#endif
    }
    const char *prog = ScrollViewProg();
    std::string command = ScrollViewCommand(scrollview_path);
    SVSync::StartProcess(prog, command.c_str());

    // Wait for server to show up.
    // Note: There is no exception handling in case the server never turns up.

    stream_ = socket(addr_info->ai_family, addr_info->ai_socktype,
                   addr_info->ai_protocol);

    while (connect(stream_, addr_info->ai_addr,
                   addr_info->ai_addrlen) < 0) {
      std::cout << "ScrollView: Waiting for server...\n";
#ifdef _WIN32
      Sleep(1000);
#else
      sleep(1);
#endif

      stream_ = socket(addr_info->ai_family, addr_info->ai_socktype,
                   addr_info->ai_protocol);
    }
  }
  FreeAddrInfo(addr_info);
}

SVNetwork::~SVNetwork() {
  delete[] msg_buffer_in_;
  delete mutex_send_;
}

#endif  // GRAPHICS_DISABLED
<|endoftext|>


<commit_before>/*********************************************************************
 * tm700_demo_node.cpp
 *
 * Copyright 2016 Copyright 2016 Techman Robot Inc.
 *
 * 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.
 *********************************************************************
 *
 * Author: Yun-Hsuan Tsai
 */

#include <ros/ros.h>
#include <ros/console.h>

#include <moveit/move_group_interface/move_group.h>
#include <moveit/planning_scene_interface/planning_scene_interface.h>
#include <moveit/robot_state/robot_state.h>
#include <moveit/robot_state/conversions.h>

#include <moveit_msgs/DisplayRobotState.h>
#include <moveit_msgs/DisplayTrajectory.h>

#include <moveit_msgs/AttachedCollisionObject.h>
#include <moveit_msgs/CollisionObject.h>

#include <stdlib.h>
#include <iostream>
#include <fstream>
#include <string>
#include <vector>
#include <cmath>

#include "tm_msgs/SetIO.h"
//#include "tm_msgs/SetIORequest.h"
//#include "tm_msgs/SetIOResponse.h"

//get current joint values of TM5
void get_current_joint_values(moveit::planning_interface::MoveGroup& group,
                              moveit::planning_interface::MoveGroup::Plan& plan,
															std::vector<double>& record_joint
														){
		//if(!ros::ok()) return false;
		bool success = false;

		std::vector<double> joint_value;
		joint_value = group.getCurrentJointValues();
    record_joint = group.getCurrentJointValues();

		for(int i = 0; i<joint_value.size(); i++){
			joint_value[i] = joint_value[i]*180/M_PI;
			printf("Joint %d: %lf\n",i+1, joint_value[i]);
		}
}

bool try_move_to_named_target(moveit::planning_interface::MoveGroup& group,
			      moveit::planning_interface::MoveGroup::Plan& plan,
			      const std::string& target_name,
			      unsigned int max_try_times = 1
			     ) {
  if(!ros::ok()) return false;
  bool success = false;

  for(unsigned int i = 0; i < max_try_times; i++) {

    group.setNamedTarget(target_name);

    if(group.move()) {
      success = true;
      break;
    }
    else {
      if(!ros::ok()) break;
      sleep(1);
    }
  }
  return success;
}

bool try_move_to_joint_target(moveit::planning_interface::MoveGroup& group,
			      moveit::planning_interface::MoveGroup::Plan& plan,
			      const std::vector<double>& joint_target,
			      unsigned int max_try_times = 1
			     ) {
  if(!ros::ok()) return false;
  bool success = false;

  for(unsigned int i = 0; i < max_try_times; i++) {

    group.setJointValueTarget(joint_target);

    if(group.move()) {
      success = true;
      break;
    }
    else {
      if(!ros::ok()) break;
      sleep(1);
    }
  }
}

int main(int argc, char **argv)
{

  ros::init(argc, argv, "tm700_demo_test");
  ros::NodeHandle node_handle;
  ros::ServiceClient set_io_client = node_handle.serviceClient<tm_msgs::SetIO>("tm_driver/set_io");
  tm_msgs::SetIO io_srv;
  io_srv.request.fun = 2;//tm_msgs::SetIORequest::FUN_SET_EE_DIGITAL_OUT;
  io_srv.request.ch = 0;
  io_srv.request.value = 0.0;

  // start a background "spinner", so our node can process ROS messages
  //  - this lets us know when the move is completed
  ros::AsyncSpinner spinner(1);
  spinner.start();

  sleep(1);

  // Setup
  // ^^^^^
  // The :move_group_interface:`MoveGroup` class can be easily
  // setup using just the name
  // of the group you would like to control and plan for.
  moveit::planning_interface::MoveGroup group("manipulator");
  // We will use the :planning_scene_interface:`PlanningSceneInterface`
  // class to deal directly with the world.
  moveit::planning_interface::PlanningSceneInterface planning_scene_interface;
  // (Optional) Create a publisher for visualizing plans in Rviz.
  //ros::Publisher display_publisher = node_handle.advertise<moveit_msgs::DisplayTrajectory>("/move_group/display_planned_path", 1, true);
  //moveit_msgs::DisplayTrajectory display_trajectory;

  // Getting Basic Information
  // ^^^^^^^^^^^^^^^^^^^^^^^^^
  // We can print the name of the reference frame for this robot.
  ROS_INFO("Reference frame: %s", group.getPlanningFrame().c_str());
  // We can also print the name of the end-effector link for this group.
  ROS_INFO("Reference frame: %s", group.getEndEffectorLink().c_str());

  moveit::planning_interface::MoveGroup::Plan my_plan;

  set_io_client.call(io_srv);

  group.setPlanningTime(30.0);

  //try_move_to_named_target(group, my_plan, "home", 100);

  std::vector<double> joint_target_1;
  std::vector<double> joint_target_2;

	std::vector<double> record_joint_1;
	std::vector<double> record_joint_2;
	std::vector<double> record_joint_3;

  double joint_value = 0;

  joint_target_1.assign(6, 0.0f);
  joint_target_1[0] = 0.0174533*( 30.0);
  joint_target_1[1] = 0.0174533*( 15.0);
  joint_target_1[2] = 0.0174533*(105.0);
  joint_target_1[3] = 0.0174533*(-30.0);
  joint_target_1[4] = 0.0174533*( 90.0);
  joint_target_1[5] = 0.0174533*( 30.0);

  joint_target_2.assign(6, 0.0f);
  joint_target_2[0] = 0.0174533*(-30.0);
  joint_target_2[1] = 0.0174533*(-15.0);
  joint_target_2[2] = 0.0174533*( 90.0);
  joint_target_2[3] = 0.0174533*(-75.0);
  joint_target_2[4] = 0.0174533*(120.0);

  int step = 0;

  while (ros::ok()) {
    switch (step) {
      case 0: //gripper off
	io_srv.request.fun = 2;
	io_srv.request.ch = 0;
	io_srv.request.value = 0.0;
	if (set_io_client.call(io_srv))
	  ROS_INFO("Set IO success");
	else
	  ROS_WARN("Failed to call service set_io");
	break;

      case 1: //move to ready
	ROS_INFO("move...");
	//try_move_to_named_target(group, my_plan, "ready", 100);
	break;

      case 2: //light on
/*
	io_srv.request.fun = 2;
	io_srv.request.ch = 3;
	io_srv.request.value = 1.0;
*/
	if (set_io_client.call(io_srv))
	  ROS_INFO("Set IO success");
	else
	  ROS_WARN("Failed to call service set_io");
	break;

      case 3: //wait 3 sec
	sleep(3);
	break;

      case 4: //light off
	io_srv.request.fun = 2;
	io_srv.request.ch = 3;
	io_srv.request.value = 0.0;
	if (set_io_client.call(io_srv))
	  ROS_INFO("Set IO success");
	else
	  ROS_WARN("Failed to call service set_io");
	break;

      case 5: //move 1
	//ROS_INFO("move...");
	//try_move_to_joint_target(group, my_plan, joint_target_1, 100);
	ROS_INFO("Read Joints Values");
	get_current_joint_values(group, my_plan, record_joint_1);
	for(int i = 0; i<record_joint_1.size(); i++){
		joint_value = record_joint_1[i]*180/M_PI;
		printf("Joint %d: degree: %lf, rad: %lf\n", i+1, joint_value, record_joint_1[i]);
	}
	break;

      case 6: //gripper on
	io_srv.request.fun = 2;
	io_srv.request.ch = 0;
	io_srv.request.value = 1.0;
	if (set_io_client.call(io_srv))
	  ROS_INFO("Set IO success");
	else
	  ROS_WARN("Failed to call service set_io");
	break;

      case 7: //wait 1 sec
	sleep(1);
	break;

      case 8: //move 2...
	ROS_INFO("move...");
	//try_move_to_joint_target(group, my_plan, joint_target_2, 100);
	break;
    }
    step = (step + 1) % 9;
  }
  return 0;
}
<commit_msg>implement get_current_joint_values in 'main'<commit_after>/*********************************************************************
 * tm700_demo_node.cpp
 *
 * Copyright 2016 Copyright 2016 Techman Robot Inc.
 *
 * 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.
 *********************************************************************
 *
 * Author: Yun-Hsuan Tsai
 */

#include <ros/ros.h>
#include <ros/console.h>

#include <moveit/move_group_interface/move_group.h>
#include <moveit/planning_scene_interface/planning_scene_interface.h>
#include <moveit/robot_state/robot_state.h>
#include <moveit/robot_state/conversions.h>

#include <moveit_msgs/DisplayRobotState.h>
#include <moveit_msgs/DisplayTrajectory.h>

#include <moveit_msgs/AttachedCollisionObject.h>
#include <moveit_msgs/CollisionObject.h>

#include <stdlib.h>
#include <iostream>
#include <fstream>
#include <string>
#include <vector>
#include <cmath>

#include "tm_msgs/SetIO.h"
//#include "tm_msgs/SetIORequest.h"
//#include "tm_msgs/SetIOResponse.h"

//get current joint values of TM5
void get_current_joint_values(moveit::planning_interface::MoveGroup& group,
                              moveit::planning_interface::MoveGroup::Plan& plan,
															std::vector<double>& record_joint
														){
		//if(!ros::ok()) return false;
		bool success = false;

		std::vector<double> joint_value;
		joint_value = group.getCurrentJointValues();
    record_joint = group.getCurrentJointValues();

		for(int i = 0; i<joint_value.size(); i++){
			joint_value[i] = joint_value[i]*180/M_PI;
			printf("Joint %d: %lf\n",i+1, joint_value[i]);
		}
}

bool try_move_to_named_target(moveit::planning_interface::MoveGroup& group,
			      moveit::planning_interface::MoveGroup::Plan& plan,
			      const std::string& target_name,
			      unsigned int max_try_times = 1
			     ) {
  if(!ros::ok()) return false;
  bool success = false;

  for(unsigned int i = 0; i < max_try_times; i++) {

    group.setNamedTarget(target_name);

    if(group.move()) {
      success = true;
      break;
    }
    else {
      if(!ros::ok()) break;
      sleep(1);
    }
  }
  return success;
}

bool try_move_to_joint_target(moveit::planning_interface::MoveGroup& group,
			      moveit::planning_interface::MoveGroup::Plan& plan,
			      const std::vector<double>& joint_target,
			      unsigned int max_try_times = 1
			     ) {
  if(!ros::ok()) return false;
  bool success = false;

  for(unsigned int i = 0; i < max_try_times; i++) {

    group.setJointValueTarget(joint_target);

    if(group.move()) {
      success = true;
      break;
    }
    else {
      if(!ros::ok()) break;
      sleep(1);
    }
  }
}

int main(int argc, char **argv)
{

  ros::init(argc, argv, "tm700_demo_test");
  ros::NodeHandle node_handle;
  ros::ServiceClient set_io_client = node_handle.serviceClient<tm_msgs::SetIO>("tm_driver/set_io");
  tm_msgs::SetIO io_srv;
  io_srv.request.fun = 2;//tm_msgs::SetIORequest::FUN_SET_EE_DIGITAL_OUT;
  io_srv.request.ch = 0;
  io_srv.request.value = 0.0;

  // start a background "spinner", so our node can process ROS messages
  //  - this lets us know when the move is completed
  ros::AsyncSpinner spinner(1);
  spinner.start();

  sleep(1);

  // Setup
  // ^^^^^
  // The :move_group_interface:`MoveGroup` class can be easily
  // setup using just the name
  // of the group you would like to control and plan for.
  moveit::planning_interface::MoveGroup group("manipulator");
  // We will use the :planning_scene_interface:`PlanningSceneInterface`
  // class to deal directly with the world.
  moveit::planning_interface::PlanningSceneInterface planning_scene_interface;
  // (Optional) Create a publisher for visualizing plans in Rviz.
  //ros::Publisher display_publisher = node_handle.advertise<moveit_msgs::DisplayTrajectory>("/move_group/display_planned_path", 1, true);
  //moveit_msgs::DisplayTrajectory display_trajectory;

  // Getting Basic Information
  // ^^^^^^^^^^^^^^^^^^^^^^^^^
  // We can print the name of the reference frame for this robot.
  ROS_INFO("Reference frame: %s", group.getPlanningFrame().c_str());
  // We can also print the name of the end-effector link for this group.
  ROS_INFO("Reference frame: %s", group.getEndEffectorLink().c_str());

  moveit::planning_interface::MoveGroup::Plan my_plan;

  set_io_client.call(io_srv);

  group.setPlanningTime(30.0);

  //try_move_to_named_target(group, my_plan, "home", 100);

  std::vector<double> joint_target_1;
  std::vector<double> joint_target_2;

	std::vector<double> record_joint_1;
	std::vector<double> record_joint_2;
	std::vector<double> record_joint_3;

  double joint_value = 0;

  joint_target_1.assign(6, 0.0f);
  joint_target_1[0] = 0.0174533*( 30.0);
  joint_target_1[1] = 0.0174533*( 15.0);
  joint_target_1[2] = 0.0174533*(105.0);
  joint_target_1[3] = 0.0174533*(-30.0);
  joint_target_1[4] = 0.0174533*( 90.0);
  joint_target_1[5] = 0.0174533*( 30.0);

  joint_target_2.assign(6, 0.0f);
  joint_target_2[0] = 0.0174533*(-30.0);
  joint_target_2[1] = 0.0174533*(-15.0);
  joint_target_2[2] = 0.0174533*( 90.0);
  joint_target_2[3] = 0.0174533*(-75.0);
  joint_target_2[4] = 0.0174533*(120.0);

  int step = 0;

  while (ros::ok()) {
    switch (step) {
      case 0: //gripper off
	io_srv.request.fun = 2;
	io_srv.request.ch = 0;
	io_srv.request.value = 0.0;
	if (set_io_client.call(io_srv))
	  ROS_INFO("Set IO success");
	else
	  ROS_WARN("Failed to call service set_io");
	break;

      case 1: //move to ready
	ROS_INFO("move...");
	//try_move_to_named_target(group, my_plan, "ready", 100);
	break;

      case 2: //light on
/*
	io_srv.request.fun = 2;
	io_srv.request.ch = 3;
	io_srv.request.value = 1.0;
*/
	if (set_io_client.call(io_srv))
	  ROS_INFO("Set IO success");
	else
	  ROS_WARN("Failed to call service set_io");
	break;

      case 3: //wait 3 sec
	sleep(3);
	break;

      case 4: //light off
	io_srv.request.fun = 2;
	io_srv.request.ch = 3;
	io_srv.request.value = 0.0;
	if (set_io_client.call(io_srv))
	  ROS_INFO("Set IO success");
	else
	  ROS_WARN("Failed to call service set_io");
	break;

      case 5: //move 1
	//ROS_INFO("move...");
	//try_move_to_joint_target(group, my_plan, joint_target_1, 100);
	ROS_INFO("Read Joints Values");
	get_current_joint_values(group, my_plan, record_joint_1);

  printf("*****************************************************************");
	for(int i = 0; i<record_joint_1.size(); i++){
		joint_value = record_joint_1[i]*180/M_PI;
		printf("Joint %d: degree: %lf, rad: %lf\n", i+1, joint_value, record_joint_1[i]);
	}
  printf("******************************************************************");</record_joint_1>
  //try_move_to_named_target(group, my_plan, "ready", 100);
  sleep(3);
/*
  try_move_to_joint_target(group, my_plan, record_joint_1, 100);
  sleep(3);
  try_move_to_joint_target(group, my_plan, joint_target_1, 100);
  sleep(3);
  try_move_to_joint_target(group, my_plan, joint_target_2, 100);
  sleep(3);
*/
	break;

      case 6: //gripper on
	io_srv.request.fun = 2;
	io_srv.request.ch = 0;
	io_srv.request.value = 1.0;
	if (set_io_client.call(io_srv))
	  ROS_INFO("Set IO success");
	else
	  ROS_WARN("Failed to call service set_io");
	break;

      case 7: //wait 1 sec
	sleep(1);
	break;

      case 8: //move 2...
	ROS_INFO("move...");
	//try_move_to_joint_target(group, my_plan, joint_target_2, 100);
	break;
    }
    step = (step + 1) % 9;
  }
  return 0;
}
<|endoftext|>


<commit_before>// $Id: mesh_refinement_smoothing.C,v 1.11 2005-05-18 18:07:36 roystgnr Exp $

// The libMesh Finite Element Library.
// Copyright (C) 2002-2005  Benjamin S. Kirk, John W. Peterson

// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; either
// version 2.1 of the License, or (at your option) any later version.

// 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

// Local includes
#include "libmesh_config.h"

// only compile these functions if the user requests AMR support
#ifdef ENABLE_AMR

#include "mesh_refinement.h"
#include "mesh_base.h"
#include "elem.h"

//-----------------------------------------------------------------
// Mesh refinement methods
bool MeshRefinement::limit_level_mismatch_at_node (const unsigned int max_mismatch)
{
  bool flags_changed = false;

  // Vector holding the maximum element level that touches a node.
  std::vector<unsigned char> max_level_at_node (_mesh.n_nodes(), 0);

  // Loop over all the active elements & fill the vector
  {
//     const_active_elem_iterator       elem_it (_mesh.const_elements_begin());
//     const const_active_elem_iterator elem_end(_mesh.const_elements_end());

    MeshBase::element_iterator       elem_it  = _mesh.active_elements_begin();
    const MeshBase::element_iterator elem_end = _mesh.active_elements_end();

    for (; elem_it != elem_end; ++elem_it)
      {
	const Elem* elem = *elem_it;
	const unsigned char elem_level =
	  elem->level() + ((elem->refinement_flag() == Elem::REFINE) ? 1 : 0);

	// Set the max_level at each node
	for (unsigned int n=0; n<elem->n_nodes(); n++)
	  {
	    const unsigned int node_number = elem->node(n);

	    assert (node_number < max_level_at_node.size());

	    max_level_at_node[node_number] =
	      std::max (max_level_at_node[node_number], elem_level);
	  }
      }
  }

  // Now loop over the active elements and flag the elements
  // who violate the requested level mismatch
  {
//     active_elem_iterator       elem_it (_mesh.elements_begin());
//     const active_elem_iterator elem_end(_mesh.elements_end());

    MeshBase::element_iterator       elem_it  = _mesh.active_elements_begin();
    const MeshBase::element_iterator elem_end = _mesh.active_elements_end();

    for (; elem_it != elem_end; ++elem_it)
      {
	Elem* elem = *elem_it;
	const unsigned int elem_level = elem->level();

	// Skip the element if it is already flagged
	if (elem->refinement_flag() == Elem::REFINE)
	  continue;

	// Loop over the nodes, check for possible mismatch
	for (unsigned int n=0; n<elem->n_nodes(); n++)
	  {
	    const unsigned int node_number = elem->node(n);

	    // Flag the element for refinement if it violates
	    // the requested level mismatch
	    if ( (elem_level + max_mismatch) < max_level_at_node[node_number])
	      {
		elem->set_refinement_flag (Elem::REFINE);
		flags_changed = true;
	      }
	  }
      }
  }

  return flags_changed;
}

bool MeshRefinement::eliminate_unrefined_patches ()
{
  bool flags_changed = false;

//   active_elem_iterator       elem_it (_mesh.elements_begin());
//   const active_elem_iterator elem_end(_mesh.elements_end());

  MeshBase::element_iterator       elem_it  = _mesh.active_elements_begin();
  const MeshBase::element_iterator elem_end = _mesh.active_elements_end();

  for (; elem_it != elem_end; ++elem_it)
    {
      Elem* elem = *elem_it;
      const unsigned int my_level = elem->level();
      bool flag_me = true;

      // Skip the element if it is already flagged for refinement
      if (elem->refinement_flag() == Elem::REFINE)
	continue;

      // Test the parent if that is already flagged for coarsening
      if (elem->refinement_flag() == Elem::COARSEN)
        {
          assert(elem->parent());
          // FIXME: this is reasonable, but why don't we have a non-const
          // Elem::parent() to begin with?
	  elem = const_cast<Elem *>(elem->parent());
          if (elem->refinement_flag() != Elem::COARSEN_INACTIVE)
            continue;
        }

      // Check all the element neighbors
      for (unsigned int n=0; n<elem->n_neighbors(); n++)
	// Quit if the element is on the boundary, or
	// if the neighbor is active and will not be refined;
	// then we do not need to refine ourselves.
	if (elem->neighbor(n) == NULL ||
	    ((elem->neighbor(n)->level() <= my_level) &&
	     (elem->neighbor(n)->active()) &&
	     (elem->neighbor(n)->refinement_flag() != Elem::REFINE))
            || (elem->neighbor(n)->refinement_flag() ==
                Elem::COARSEN_INACTIVE))
          {
	    flag_me = false;
            break;
          }

      if (flag_me)
	{
	  // Parents that would create islands should no longer
          // coarsen
          if (elem->refinement_flag() == Elem::COARSEN_INACTIVE)
            {
              for (unsigned int c=0; c<elem->n_children(); c++)
                {
                  assert(elem->child(c)->refinement_flag() ==
                         Elem::COARSEN);
                  elem->child(c)->set_refinement_flag(Elem::DO_NOTHING);
                }
              elem->set_refinement_flag(Elem::INACTIVE);
            }
          else
	    elem->set_refinement_flag(Elem::REFINE);
	  flags_changed = true;
	}
    }

  return flags_changed;
}

#endif
<commit_msg>Fix false positives in detection of unrefined islands.<commit_after>// $Id: mesh_refinement_smoothing.C,v 1.12 2006-04-17 21:18:09 roystgnr Exp $

// The libMesh Finite Element Library.
// Copyright (C) 2002-2005  Benjamin S. Kirk, John W. Peterson

// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; either
// version 2.1 of the License, or (at your option) any later version.

// 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

// Local includes
#include "libmesh_config.h"

// only compile these functions if the user requests AMR support
#ifdef ENABLE_AMR

#include "mesh_refinement.h"
#include "mesh_base.h"
#include "elem.h"

//-----------------------------------------------------------------
// Mesh refinement methods
bool MeshRefinement::limit_level_mismatch_at_node (const unsigned int max_mismatch)
{
  bool flags_changed = false;

  // Vector holding the maximum element level that touches a node.
  std::vector<unsigned char> max_level_at_node (_mesh.n_nodes(), 0);

  // Loop over all the active elements & fill the vector
  {
//     const_active_elem_iterator       elem_it (_mesh.const_elements_begin());
//     const const_active_elem_iterator elem_end(_mesh.const_elements_end());

    MeshBase::element_iterator       elem_it  = _mesh.active_elements_begin();
    const MeshBase::element_iterator elem_end = _mesh.active_elements_end();

    for (; elem_it != elem_end; ++elem_it)
      {
	const Elem* elem = *elem_it;
	const unsigned char elem_level =
	  elem->level() + ((elem->refinement_flag() == Elem::REFINE) ? 1 : 0);

	// Set the max_level at each node
	for (unsigned int n=0; n<elem->n_nodes(); n++)
	  {
	    const unsigned int node_number = elem->node(n);

	    assert (node_number < max_level_at_node.size());

	    max_level_at_node[node_number] =
	      std::max (max_level_at_node[node_number], elem_level);
	  }
      }
  }

  // Now loop over the active elements and flag the elements
  // who violate the requested level mismatch
  {
//     active_elem_iterator       elem_it (_mesh.elements_begin());
//     const active_elem_iterator elem_end(_mesh.elements_end());

    MeshBase::element_iterator       elem_it  = _mesh.active_elements_begin();
    const MeshBase::element_iterator elem_end = _mesh.active_elements_end();

    for (; elem_it != elem_end; ++elem_it)
      {
	Elem* elem = *elem_it;
	const unsigned int elem_level = elem->level();

	// Skip the element if it is already flagged
	if (elem->refinement_flag() == Elem::REFINE)
	  continue;

	// Loop over the nodes, check for possible mismatch
	for (unsigned int n=0; n<elem->n_nodes(); n++)
	  {
	    const unsigned int node_number = elem->node(n);

	    // Flag the element for refinement if it violates
	    // the requested level mismatch
	    if ( (elem_level + max_mismatch) < max_level_at_node[node_number])
	      {
		elem->set_refinement_flag (Elem::REFINE);
		flags_changed = true;
	      }
	  }
      }
  }

  return flags_changed;
}

bool MeshRefinement::eliminate_unrefined_patches ()
{
  bool flags_changed = false;

//   active_elem_iterator       elem_it (_mesh.elements_begin());
//   const active_elem_iterator elem_end(_mesh.elements_end());

  MeshBase::element_iterator       elem_it  = _mesh.active_elements_begin();
  const MeshBase::element_iterator elem_end = _mesh.active_elements_end();

  for (; elem_it != elem_end; ++elem_it)
    {
      Elem* elem = *elem_it;
      const unsigned int my_level = elem->level();
      bool flag_me = true;

      // Skip the element if it is already flagged for refinement
      if (elem->refinement_flag() == Elem::REFINE)
	continue;

      // Test the parent if that is already flagged for coarsening
      if (elem->refinement_flag() == Elem::COARSEN)
        {
          assert(elem->parent());
          // FIXME: this is reasonable, but why don't we have a non-const
          // Elem::parent() to begin with?
	  elem = const_cast<Elem *>(elem->parent());
          if (elem->refinement_flag() != Elem::COARSEN_INACTIVE)
            continue;
        }

      // Check all the element neighbors
      for (unsigned int n=0; n<elem->n_neighbors(); n++)
	// Quit if the element is on the boundary, or
	// if the neighbor is active and will not be refined;
	// then we do not need to refine ourselves.
	if (elem->neighbor(n) == NULL ||
	    (elem->neighbor(n)->level() < my_level) ||
	    ((elem->neighbor(n)->active()) &&
	     (elem->neighbor(n)->refinement_flag() != Elem::REFINE))
            || (elem->neighbor(n)->refinement_flag() ==
                Elem::COARSEN_INACTIVE))
          {
	    flag_me = false;
            break;
          }

      if (flag_me)
	{
	  // Parents that would create islands should no longer
          // coarsen
          if (elem->refinement_flag() == Elem::COARSEN_INACTIVE)
            {
              for (unsigned int c=0; c<elem->n_children(); c++)
                {
                  assert(elem->child(c)->refinement_flag() ==
                         Elem::COARSEN);
                  elem->child(c)->set_refinement_flag(Elem::DO_NOTHING);
                }
              elem->set_refinement_flag(Elem::INACTIVE);
            }
          else
	    elem->set_refinement_flag(Elem::REFINE);
	  flags_changed = true;
	}
    }

  return flags_changed;
}

#endif
<|endoftext|>


<commit_before>// Copyright 2004-present Facebook. All Rights Reserved.

#include "osquery/tables/system/processes.h"

#include <algorithm>
#include <map>
#include <vector>
#include <string>

#include <libproc.h>
#include <stdlib.h>

#include <boost/filesystem/operations.hpp>
#include <boost/filesystem/path.hpp>
#include <boost/lexical_cast.hpp>

#include <glog/logging.h>

#include "osquery/core.h"

using namespace osquery::core;
using namespace osquery::db;

namespace osquery { namespace tables {

QueryData genProcesses() {
  QueryData results;
  std::vector<int> processed;
  std::map<int, int> parent_pid;

  // find how how many pids there are so that we can create an appropriately
  // sized data structure to store them
  int num_pids = proc_listpids(PROC_ALL_PIDS, 0, NULL, 0);
  if (num_pids <= 0) {
    LOG(ERROR) << "An error occured retrieving the process list";
    return {};
  }

  // arbitrarily create a list with 2x capacity in case more processes have
  // been loaded since the last proc_listpids was executed
  pid_t pids[num_pids * 2];
  memset(pids, 0, sizeof(pids));
  int s = proc_listpids(PROC_ALL_PIDS, 0, pids, sizeof(pids));
  if (s <= 0) {
    LOG(ERROR) << "An error occured retrieving the process list";
    return {};
  }

  for (const auto& pid : pids) {
    pid_t children[num_pids * 2];
    memset(children, 0, sizeof(children));
    proc_listchildpids(pid, children, sizeof(children));
    for (const auto& child : children) {
      parent_pid[child] = pid;
    }
  }

  for (const auto& pid : pids) {
    // if the pid is negative or 0, it doesn't represent a real process so
    // continue the iterations so that we don't add it to the results set
    if (pid <= 0) {
      continue;
    }

    // ensure that we process a pid once and only once
    if (std::find(processed.begin(), processed.end(), pid) != processed.end()) {
      continue;
    }
    processed.push_back(pid);

    // gather column data
    Row r;

    const auto parent_it = parent_pid.find(pid);
    if (parent_it != parent_pid.end()) {
      r["parent"] = boost::lexical_cast<std::string>(parent_it->second);
    } else {
      r["parent"] = "-1";
    }

    // process id
    r["pid"] = boost::lexical_cast<std::string>(pid);

    // process name
    char name[1024];
    memset(name, 0, 1024);
    proc_name(pid, name, sizeof(name));
    r["name"] = std::string(name);

    // if the path of the executable that started the process is available
    // and the path exists on disk, set on_disk to true. if the path is not
    // available, set on_disk to true. if, and only if, the path of the
    // executable is available and the file does not exist on disk, set on_disk
    // to false.
    char path[PROC_PIDPATHINFO_MAXSIZE];
    memset(path, 0, sizeof(path));
    proc_pidpath(pid, path, sizeof(path));
    r["path"] = std::string(path);
    if (strlen(path) > 0) {
      if (!boost::filesystem::exists(r["path"])) {
        r["on_disk"] = "0";
      } else {
        r["on_disk"] = "1";
      }
    } else {
      r["on_disk"] = "1";
    }

    // systems usage and time information
    struct rusage_info_v2 rusage_info_data;
    int rusage_status = proc_pid_rusage(
      pid, RUSAGE_INFO_V2, (rusage_info_t*)&rusage_info_data);
    // proc_pid_rusage returns -1 if it was unable to gather information
    if (rusage_status == 0) {
      // size information
      r["wired_size"] = boost::lexical_cast<std::string>(
        rusage_info_data.ri_wired_size);
      r["resident_size"] = boost::lexical_cast<std::string>(
        rusage_info_data.ri_resident_size);
      r["phys_footprint"] = boost::lexical_cast<std::string>(
        rusage_info_data.ri_phys_footprint);

      // time information
      r["user_time"] = boost::lexical_cast<std::string>(
        rusage_info_data.ri_user_time);
      r["system_time"] = boost::lexical_cast<std::string>(
        rusage_info_data.ri_system_time);
      r["start_time"] = boost::lexical_cast<std::string>(
        rusage_info_data.ri_proc_start_abstime);
    }

    // save the results
    results.push_back(r);
  }

  return results;
}

}}
<commit_msg>unordered_map and better logic around on_disk<commit_after>// Copyright 2004-present Facebook. All Rights Reserved.

#include "osquery/tables/system/processes.h"

#include <algorithm>
#include <map>
#include <vector>
#include <string>

#include <libproc.h>
#include <stdlib.h>

#include <boost/filesystem/operations.hpp>
#include <boost/filesystem/path.hpp>
#include <boost/lexical_cast.hpp>

#include <glog/logging.h>

#include "osquery/core.h"

using namespace osquery::core;
using namespace osquery::db;

namespace osquery { namespace tables {

QueryData genProcesses() {
  QueryData results;
  std::vector<int> processed;
  std::unordered_map<int, int> parent_pid;

  // find how how many pids there are so that we can create an appropriately
  // sized data structure to store them
  int num_pids = proc_listpids(PROC_ALL_PIDS, 0, NULL, 0);
  if (num_pids <= 0) {
    LOG(ERROR) << "An error occured retrieving the process list";
    return {};
  }

  // arbitrarily create a list with 2x capacity in case more processes have
  // been loaded since the last proc_listpids was executed
  pid_t pids[num_pids * 2];
  memset(pids, 0, sizeof(pids));
  int s = proc_listpids(PROC_ALL_PIDS, 0, pids, sizeof(pids));
  if (s <= 0) {
    LOG(ERROR) << "An error occured retrieving the process list";
    return {};
  }

  for (const auto& pid : pids) {
    pid_t children[num_pids * 2];
    memset(children, 0, sizeof(children));
    proc_listchildpids(pid, children, sizeof(children));
    for (const auto& child : children) {
      parent_pid[child] = pid;
    }
  }

  for (const auto& pid : pids) {
    // if the pid is negative or 0, it doesn't represent a real process so
    // continue the iterations so that we don't add it to the results set
    if (pid <= 0) {
      continue;
    }

    // ensure that we process a pid once and only once
    if (std::find(processed.begin(), processed.end(), pid) != processed.end()) {
      continue;
    }
    processed.push_back(pid);

    // gather column data
    Row r;

    const auto parent_it = parent_pid.find(pid);
    if (parent_it != parent_pid.end()) {
      r["parent"] = boost::lexical_cast<std::string>(parent_it->second);
    } else {
      r["parent"] = "-1";
    }

    // process id
    r["pid"] = boost::lexical_cast<std::string>(pid);

    // process name
    char name[1024];
    memset(name, 0, 1024);
    proc_name(pid, name, sizeof(name));
    r["name"] = std::string(name);

    // if the path of the executable that started the process is available and
    // the path exists on disk, set on_disk to 1.  if the path is not
    // available, set on_disk to -1.  if, and only if, the path of the
    // executable is available and the file does not exist on disk, set on_disk
    // to 0.
    char path[PROC_PIDPATHINFO_MAXSIZE];
    memset(path, 0, sizeof(path));
    proc_pidpath(pid, path, sizeof(path));
    r["path"] = std::string(path);
    if (strlen(path) > 0) {
      if (!boost::filesystem::exists(r["path"])) {
        r["on_disk"] = "0";
      } else {
        r["on_disk"] = "1";
      }
    } else {
      r["on_disk"] = "-1";
    }

    // systems usage and time information
    struct rusage_info_v2 rusage_info_data;
    int rusage_status = proc_pid_rusage(
      pid, RUSAGE_INFO_V2, (rusage_info_t*)&rusage_info_data);
    // proc_pid_rusage returns -1 if it was unable to gather information
    if (rusage_status == 0) {
      // size information
      r["wired_size"] = boost::lexical_cast<std::string>(
        rusage_info_data.ri_wired_size);
      r["resident_size"] = boost::lexical_cast<std::string>(
        rusage_info_data.ri_resident_size);
      r["phys_footprint"] = boost::lexical_cast<std::string>(
        rusage_info_data.ri_phys_footprint);

      // time information
      r["user_time"] = boost::lexical_cast<std::string>(
        rusage_info_data.ri_user_time);
      r["system_time"] = boost::lexical_cast<std::string>(
        rusage_info_data.ri_system_time);
      r["start_time"] = boost::lexical_cast<std::string>(
        rusage_info_data.ri_proc_start_abstime);
    }

    // save the results
    results.push_back(r);
  }

  return results;
}

}}
<|endoftext|>


<commit_before>#include "stdafx.h"
#include "sceneGraph.h"

#include "CommonLog.h"

#include <maya/MItDag.h>
#include <maya/MFnDagNode.h>

static MString __PythonBool[] = { MString("False"), MString("True") };
static inline const MString &PythonBool(bool b)
{
	return __PythonBool[b?1:0];
}

static void __file_and_time_control_kill(const MString &var)
{
	MGlobal::executePythonCommand(var + " = None\n");	// deallocate this variable in Python!
}

AlembicFileAndTimeControl::~AlembicFileAndTimeControl(void)
{
	__file_and_time_control_kill(var);
}

AlembicFileAndTimeControlPtr AlembicFileAndTimeControl::createControl(const IJobStringParser& jobParams)
{
	static unsigned int numberOfControlCreated = 0;
	static const MString format("^1s = ExoAlembic._import.IJobInfo(r\"^2s\", ^3s, ^4s, ^5s)\n");

	ESS_PROFILE_SCOPE("AlembicFileAndTimeControl::createControl");
	MString var("__alembic_file_and_time_control_tuple_");
	var += (++numberOfControlCreated);

	MString cmd;
	cmd.format(format, var, jobParams.filename.c_str(), PythonBool(jobParams.importNormals), PythonBool(jobParams.importUVs), PythonBool(jobParams.importFacesets));
	MStatus status = MGlobal::executePythonCommand(cmd);
	if (status != MS::kSuccess)
	{
		__file_and_time_control_kill(var);
		return AlembicFileAndTimeControlPtr();
	}
	return AlembicFileAndTimeControlPtr(new AlembicFileAndTimeControl(var));
}

bool SceneNodeMaya::replaceSimilarData(const char *functionName, SceneNodeAlembicPtr fileNode)
{
	static const MString format("ExoAlembic._attach.attach^1s(r\"^2s\", r\"^3s\", ^4s, ^5s)");

	ESS_PROFILE_SCOPE("SceneNodeMaya::replaceSimilarData");
	MString cmd;
	cmd.format(format, functionName, fileNode->name.c_str(), fileNode->dccIdentifier.c_str(), fileAndTime->variable(), PythonBool(fileNode->pObjCache->isConstant));
	MGlobal::executePythonCommand(cmd);
	fileNode->setAttached(true);
	return true;
}

bool SceneNodeMaya::replaceData(SceneNodeAlembicPtr fileNode, const IJobStringParser& jobParams, SceneNodeAlembicPtr& nextFileNode)
{
	ESS_PROFILE_SCOPE("SceneNodeMaya::replaceData");
	nextFileNode = fileNode;
	switch(nextFileNode->type)
	{
	case ETRANSFORM:
	case ITRANSFORM:
		return replaceSimilarData("Xform", fileNode);
	case CAMERA:
		return replaceSimilarData("Camera", fileNode);
	case POLYMESH:
	case SUBD:
		return replaceSimilarData("PolyMesh", fileNode);
	case CURVES:
	case HAIR:
		return replaceSimilarData("Curves", fileNode);
	case PARTICLES:
		return replaceSimilarData("Points", fileNode);
	//case SURFACE:	// handle as default for now
		//break;
	//case LIGHT:	// handle as default for now
		//break;
	default:
		break;
	}
	return false;
}

bool SceneNodeMaya::executeAddChild(const MString &cmd, SceneNodeAppPtr& newAppNode)
{
	MString result;
	MGlobal::executePythonCommand(cmd, result);
	if (result.length() == 0)
		return false;
	else if (result.asChar()[0] == '?')
	{
#ifdef _DEBUG
		MGlobal::displayError(result);
		MGlobal::displayError(cmd);
#endif
		return false;
	}

	newAppNode->dccIdentifier = result.asChar();
	newAppNode->name = newAppNode->dccIdentifier;
	return true;
}

bool SceneNodeMaya::addSimilarChild(const char *functionName, SceneNodeAlembicPtr fileNode, SceneNodeAppPtr& newAppNode)
{
	static const MString format("ExoAlembic._import.import^1s(r\"^2s\", r\"^3s\", ^4s, r\"^5s\", ^6s)");

	ESS_PROFILE_SCOPE("SceneNodeMaya::addSimilarChild");
	MString cmd;
	cmd.format(format, functionName, fileNode->name.c_str(), fileNode->dccIdentifier.c_str(), fileAndTime->variable(), dccIdentifier.c_str(), PythonBool(fileNode->pObjCache->isConstant));
	return executeAddChild(cmd, newAppNode);
}

bool SceneNodeMaya::addXformChild(SceneNodeAlembicPtr fileNode, SceneNodeAppPtr& newAppNode)
{
	static const MString format("ExoAlembic._import.importXform(r\"^1s\", r\"^2s\", ^3s, ^4s, ^5s)");

	ESS_PROFILE_SCOPE("SceneNodeMaya::addXformChild");
	MString parent;
	switch(type)
	{
	case ETRANSFORM:
	case ITRANSFORM:
		parent.format("\"^1s\"", dccIdentifier.c_str());
		break;
	default:
		parent = "None";
		break;
	}

	MString cmd;
	cmd.format(format, fileNode->name.c_str(), fileNode->dccIdentifier.c_str(), fileAndTime->variable(), parent, PythonBool(fileNode->pObjCache->isConstant));
	return executeAddChild(cmd, newAppNode);
}

bool SceneNodeMaya::addPolyMeshChild(SceneNodeAlembicPtr fileNode, SceneNodeAppPtr& newAppNode)
{
	static const MString format("ExoAlembic._import.importPolyMesh(r\"^1s\", r\"^2s\", ^3s, \"^4s\", ^5s, ^6s)");

	ESS_PROFILE_SCOPE("SceneNodeMaya::addPolyMeshChild");
	MString cmd;
	cmd.format(format,	fileNode->name.c_str(),	fileNode->dccIdentifier.c_str(),				fileAndTime->variable(),
						dccIdentifier.c_str(),	PythonBool(fileNode->pObjCache->isConstant),	PythonBool(fileNode->pObjCache->isMeshTopoDynamic));
	return executeAddChild(cmd, newAppNode);
}

bool SceneNodeMaya::addCurveChild(SceneNodeAlembicPtr fileNode, SceneNodeAppPtr& newAppNode)
{
	static const MString format("ExoAlembic._import.importCurves(r\"^1s\", r\"^2s\", ^3s, r\"^4s\", ^5s, ^6s)");

	MString strNb;
	{
		AbcG::ICurvesSchema::Sample sample;
		AbcG::ICurves obj(fileNode->getObject(), Abc::kWrapExisting);
		obj.getSchema().get(sample, 0);

		strNb += (unsigned int)sample.getCurvesNumVertices()->size();
	}

	MString cmd;
	cmd.format(format, fileNode->name.c_str(), fileNode->dccIdentifier.c_str(), fileAndTime->variable(), dccIdentifier.c_str(), PythonBool(fileNode->pObjCache->isConstant), strNb);
	return executeAddChild(cmd, newAppNode);
}

bool SceneNodeMaya::addChild(SceneNodeAlembicPtr fileNode, const IJobStringParser& jobParams, SceneNodeAppPtr& newAppNode)
{
	ESS_PROFILE_SCOPE("SceneNodeMaya::addChild");
	newAppNode.reset(new SceneNodeMaya(fileAndTime));
	switch(newAppNode->type = fileNode->type)
	{
	case ETRANSFORM:
	case ITRANSFORM:
		return addXformChild(fileNode, newAppNode);
	case CAMERA:
		return addSimilarChild("Camera", fileNode, newAppNode);
	case POLYMESH:
	case SUBD:
		return addPolyMeshChild(fileNode, newAppNode);
	case CURVES:
	case HAIR:
		return addCurveChild(fileNode, newAppNode);
	case PARTICLES:
		return addSimilarChild("Points", fileNode, newAppNode);
	//case SURFACE:	// handle as default for now
		//break;
	//case LIGHT:	// handle as default for now
		//break;
	default:
		break;
	}
	return false;
}

void SceneNodeMaya::print(void)
{
	ESS_LOG_WARNING("Maya Scene Node: " << dccIdentifier);
}

static bool visitChild(const MObject &mObj, SceneNodeAppPtr &parent, const AlembicFileAndTimeControlPtr &alembicFileAndTimeControl, const SearchReplace::ReplacePtr &replacer)
{
	// check if it's a valid type of node first!
	SceneNodeAppPtr exoChild(new SceneNodeMaya(alembicFileAndTimeControl));
	switch(mObj.apiType())
	{
	case MFn::kCamera:
		exoChild->type = SceneNode::CAMERA;
		break;
	case MFn::kMesh:
		exoChild->type = SceneNode::POLYMESH;
		break;
	case MFn::kSubdiv:
		exoChild->type = SceneNode::SUBD;
		break;
	case MFn::kNurbsCurve:
		exoChild->type = SceneNode::CURVES;
		break;
	case MFn::kParticle:
		exoChild->type = SceneNode::PARTICLES;
		break;
	case MFn::kPfxHair:
		exoChild->type = SceneNode::HAIR;
		break;
	case MFn::kTransform:
	default:
		exoChild->type = SceneNode::ETRANSFORM;
		break;
	}

	parent->children.push_back(exoChild);
	exoChild->parent = parent.get();

	MFnDagNode dagNode(mObj);
	exoChild->dccIdentifier = dagNode.fullPathName().asChar();
	exoChild->name = replacer->replace(dagNode.partialPathName().asChar());
	for (unsigned int i = 0; i < dagNode.childCount(); ++i)
		visitChild(dagNode.child(i), exoChild, alembicFileAndTimeControl, replacer);
	return true;
}

SceneNodeAppPtr buildMayaSceneGraph(const MDagPath &dagPath, const SearchReplace::ReplacePtr &replacer, const AlembicFileAndTimeControlPtr alembicFileAndTimeControl)
{
	ESS_PROFILE_SCOPE("buildMayaSceneGraph");
	SceneNodeAppPtr exoRoot(new SceneNodeMaya(alembicFileAndTimeControl));
	exoRoot->type = SceneNode::SCENE_ROOT;
	exoRoot->dccIdentifier = dagPath.fullPathName().asChar();
	exoRoot->name = dagPath.partialPathName().asChar();
	for (unsigned int i = 0; i < dagPath.childCount(); ++i)
		visitChild(dagPath.child(i), exoRoot, alembicFileAndTimeControl, replacer);
	return exoRoot;
}

<commit_msg>fixed #271 no more problem with the unnamed transform node. But the hair still don't export properly.<commit_after>#include "stdafx.h"
#include "sceneGraph.h"

#include "CommonLog.h"

#include <maya/MItDag.h>
#include <maya/MFnDagNode.h>

static MString __PythonBool[] = { MString("False"), MString("True") };
static inline const MString &PythonBool(bool b)
{
	return __PythonBool[b?1:0];
}

static void __file_and_time_control_kill(const MString &var)
{
	MGlobal::executePythonCommand(var + " = None\n");	// deallocate this variable in Python!
}

AlembicFileAndTimeControl::~AlembicFileAndTimeControl(void)
{
	__file_and_time_control_kill(var);
}

AlembicFileAndTimeControlPtr AlembicFileAndTimeControl::createControl(const IJobStringParser& jobParams)
{
	static unsigned int numberOfControlCreated = 0;
	static const MString format("^1s = ExoAlembic._import.IJobInfo(r\"^2s\", ^3s, ^4s, ^5s)\n");

	ESS_PROFILE_SCOPE("AlembicFileAndTimeControl::createControl");
	MString var("__alembic_file_and_time_control_tuple_");
	var += (++numberOfControlCreated);

	MString cmd;
	cmd.format(format, var, jobParams.filename.c_str(), PythonBool(jobParams.importNormals), PythonBool(jobParams.importUVs), PythonBool(jobParams.importFacesets));
	MStatus status = MGlobal::executePythonCommand(cmd);
	if (status != MS::kSuccess)
	{
		__file_and_time_control_kill(var);
		return AlembicFileAndTimeControlPtr();
	}
	return AlembicFileAndTimeControlPtr(new AlembicFileAndTimeControl(var));
}

bool SceneNodeMaya::replaceSimilarData(const char *functionName, SceneNodeAlembicPtr fileNode)
{
	static const MString format("ExoAlembic._attach.attach^1s(r\"^2s\", r\"^3s\", ^4s, ^5s)");

	ESS_PROFILE_SCOPE("SceneNodeMaya::replaceSimilarData");
	MString cmd;
	cmd.format(format, functionName, fileNode->name.c_str(), fileNode->dccIdentifier.c_str(), fileAndTime->variable(), PythonBool(fileNode->pObjCache->isConstant));
	MGlobal::executePythonCommand(cmd);
	fileNode->setAttached(true);
	return true;
}

bool SceneNodeMaya::replaceData(SceneNodeAlembicPtr fileNode, const IJobStringParser& jobParams, SceneNodeAlembicPtr& nextFileNode)
{
	ESS_PROFILE_SCOPE("SceneNodeMaya::replaceData");
	nextFileNode = fileNode;
	switch(nextFileNode->type)
	{
	case ETRANSFORM:
	case ITRANSFORM:
		return replaceSimilarData("Xform", fileNode);
	case CAMERA:
		return replaceSimilarData("Camera", fileNode);
	case POLYMESH:
	case SUBD:
		return replaceSimilarData("PolyMesh", fileNode);
	case CURVES:
	case HAIR:
		return replaceSimilarData("Curves", fileNode);
	case PARTICLES:
		return replaceSimilarData("Points", fileNode);
	//case SURFACE:	// handle as default for now
		//break;
	//case LIGHT:	// handle as default for now
		//break;
	default:
		break;
	}
	return false;
}

bool SceneNodeMaya::executeAddChild(const MString &cmd, SceneNodeAppPtr& newAppNode)
{
	MString result;
	MGlobal::executePythonCommand(cmd, result);
	if (result.length() == 0)
		return false;
	else if (result.asChar()[0] == '?')
	{
#ifdef _DEBUG
		MGlobal::displayError(result);
		MGlobal::displayError(cmd);
#endif
		return false;
	}

	newAppNode->dccIdentifier = result.asChar();
	newAppNode->name = newAppNode->dccIdentifier;
	return true;
}

bool SceneNodeMaya::addSimilarChild(const char *functionName, SceneNodeAlembicPtr fileNode, SceneNodeAppPtr& newAppNode)
{
	static const MString format("ExoAlembic._import.import^1s(r\"^2s\", r\"^3s\", ^4s, r\"^5s\", ^6s)");

	ESS_PROFILE_SCOPE("SceneNodeMaya::addSimilarChild");
	MString cmd;
	cmd.format(format, functionName, fileNode->name.c_str(), fileNode->dccIdentifier.c_str(), fileAndTime->variable(), dccIdentifier.c_str(), PythonBool(fileNode->pObjCache->isConstant));
	return executeAddChild(cmd, newAppNode);
}

bool SceneNodeMaya::addXformChild(SceneNodeAlembicPtr fileNode, SceneNodeAppPtr& newAppNode)
{
	static const MString format("ExoAlembic._import.importXform(r\"^1s\", r\"^2s\", ^3s, ^4s, ^5s)");

	ESS_PROFILE_SCOPE("SceneNodeMaya::addXformChild");
	MString parent;
	switch(type)
	{
	case ETRANSFORM:
	case ITRANSFORM:
		parent.format("\"^1s\"", dccIdentifier.c_str());
		break;
	default:
		parent = "None";
		break;
	}

	MString cmd;
	cmd.format(format, fileNode->name.c_str(), fileNode->dccIdentifier.c_str(), fileAndTime->variable(), parent, PythonBool(fileNode->pObjCache->isConstant));
	return executeAddChild(cmd, newAppNode);
}

bool SceneNodeMaya::addPolyMeshChild(SceneNodeAlembicPtr fileNode, SceneNodeAppPtr& newAppNode)
{
	static const MString format("ExoAlembic._import.importPolyMesh(r\"^1s\", r\"^2s\", ^3s, \"^4s\", ^5s, ^6s)");

	ESS_PROFILE_SCOPE("SceneNodeMaya::addPolyMeshChild");
	MString cmd;
	cmd.format(format,	fileNode->name.c_str(),	fileNode->dccIdentifier.c_str(),				fileAndTime->variable(),
						dccIdentifier.c_str(),	PythonBool(fileNode->pObjCache->isConstant),	PythonBool(fileNode->pObjCache->isMeshTopoDynamic));
	return executeAddChild(cmd, newAppNode);
}

bool SceneNodeMaya::addCurveChild(SceneNodeAlembicPtr fileNode, SceneNodeAppPtr& newAppNode)
{
	static const MString format("ExoAlembic._import.importCurves(r\"^1s\", r\"^2s\", ^3s, r\"^4s\", ^5s, ^6s)");

	MString strNb;
	{
		AbcG::ICurvesSchema::Sample sample;
		AbcG::ICurves obj(fileNode->getObject(), Abc::kWrapExisting);
		obj.getSchema().get(sample, 0);

		strNb += (unsigned int)sample.getCurvesNumVertices()->size();
	}

	MString cmd;
	cmd.format(format, fileNode->name.c_str(), fileNode->dccIdentifier.c_str(), fileAndTime->variable(), dccIdentifier.c_str(), PythonBool(fileNode->pObjCache->isConstant), strNb);
	return executeAddChild(cmd, newAppNode);
}

bool SceneNodeMaya::addChild(SceneNodeAlembicPtr fileNode, const IJobStringParser& jobParams, SceneNodeAppPtr& newAppNode)
{
	ESS_PROFILE_SCOPE("SceneNodeMaya::addChild");
	newAppNode.reset(new SceneNodeMaya(fileAndTime));
	switch(newAppNode->type = fileNode->type)
	{
	case ETRANSFORM:
	case ITRANSFORM:
		return addXformChild(fileNode, newAppNode);
	case CAMERA:
		return addSimilarChild("Camera", fileNode, newAppNode);
	case POLYMESH:
	case SUBD:
		return addPolyMeshChild(fileNode, newAppNode);
	case CURVES:
	case HAIR:
		return addCurveChild(fileNode, newAppNode);
	case PARTICLES:
		return addSimilarChild("Points", fileNode, newAppNode);
	//case SURFACE:	// handle as default for now
		//break;
	//case LIGHT:	// handle as default for now
		//break;
	default:
		break;
	}
	return false;
}

void SceneNodeMaya::print(void)
{
	ESS_LOG_WARNING("Maya Scene Node: " << dccIdentifier);
}

static bool visitChild(const MObject &mObj, SceneNodeAppPtr &parent, const AlembicFileAndTimeControlPtr &alembicFileAndTimeControl, const SearchReplace::ReplacePtr &replacer)
{
	// check if it's a valid type of node first!
	SceneNodeAppPtr exoChild(new SceneNodeMaya(alembicFileAndTimeControl));
	switch(mObj.apiType())
	{
	case MFn::kCamera:
		exoChild->type = SceneNode::CAMERA;
		break;
	case MFn::kMesh:
		exoChild->type = SceneNode::POLYMESH;
		break;
	case MFn::kSubdiv:
		exoChild->type = SceneNode::SUBD;
		break;
	case MFn::kNurbsCurve:
		exoChild->type = SceneNode::CURVES;
		break;
	case MFn::kParticle:
		exoChild->type = SceneNode::PARTICLES;
		break;
	case MFn::kPfxHair:
		exoChild->type = SceneNode::HAIR;
		break;
	case MFn::kTransform:
	default:
		exoChild->type = SceneNode::ETRANSFORM;
		break;
	}

	MFnDagNode dagNode(mObj);
	const std::string dccId = dagNode.fullPathName().asChar();
	if (dccId.length() == 0)
		return true;

	parent->children.push_back(exoChild);
	exoChild->parent = parent.get();

	exoChild->dccIdentifier = dccId;
	exoChild->name = replacer->replace(dagNode.partialPathName().asChar());
	for (unsigned int i = 0; i < dagNode.childCount(); ++i)
		visitChild(dagNode.child(i), exoChild, alembicFileAndTimeControl, replacer);
	return true;
}

SceneNodeAppPtr buildMayaSceneGraph(const MDagPath &dagPath, const SearchReplace::ReplacePtr &replacer, const AlembicFileAndTimeControlPtr alembicFileAndTimeControl)
{
	ESS_PROFILE_SCOPE("buildMayaSceneGraph");
	SceneNodeAppPtr exoRoot(new SceneNodeMaya(alembicFileAndTimeControl));
	exoRoot->type = SceneNode::SCENE_ROOT;
	exoRoot->dccIdentifier = dagPath.fullPathName().asChar();
	exoRoot->name = dagPath.partialPathName().asChar();
	for (unsigned int i = 0; i < dagPath.childCount(); ++i)
		visitChild(dagPath.child(i), exoRoot, alembicFileAndTimeControl, replacer);
	return exoRoot;
}

<|endoftext|>


<commit_before>#include "formulation/scalar/cfem_diffusion.h"

#include <array>
#include <memory>
#include <cstdlib>

#include "data/cross_sections.h"
#include "domain/tests/finite_element_mock.h"
#include "material/tests/mock_material.h"
#include "test_helpers/gmock_wrapper.h"
#include "test_helpers/test_helper_functions.h"

namespace {

using ::testing::AssertionResult;
using ::testing::AssertionFailure;
using ::testing::AssertionSuccess;
using ::testing::Le;
using ::testing::Ge;
using ::testing::DoDefault;
using ::testing::NiceMock;
using ::testing::Return;
using ::testing::_;
using namespace bart;

class FormulationCFEMDiffusionTest : public ::testing::Test {
 protected:
  using Matrix = dealii::FullMatrix<double>;
  std::shared_ptr<domain::FiniteElementMock<2>> fe_mock_ptr;
  std::shared_ptr<data::CrossSections> cross_sections_ptr;

  void SetUp() override;
};

void FormulationCFEMDiffusionTest::SetUp() {
  // Make mock objects. Cross-sections is a struct that cannot be mocked, but
  // we can mock the material object it is based on.
  NiceMock<btest::MockMaterial> mock_material;
  fe_mock_ptr = std::make_shared<NiceMock<domain::FiniteElementMock<2>>>();

  ON_CALL(*fe_mock_ptr, dofs_per_cell())
      .WillByDefault(Return(2));
  ON_CALL(*fe_mock_ptr, n_cell_quad_pts())
      .WillByDefault(Return(2));
  ON_CALL(*fe_mock_ptr, n_face_quad_pts())
      .WillByDefault(Return(2));

  for (int q = 0; q < 2; ++q) {
    ON_CALL(*fe_mock_ptr, Jacobian(q))
        .WillByDefault(Return((1 + q)*3));
    for (int i = 0; i < 2; ++i) {
      ON_CALL(*fe_mock_ptr, ShapeValue(i, q))
          .WillByDefault(Return(i + q));

      dealii::Tensor<1, 2> gradient_tensor;
      gradient_tensor[0] = i;
      gradient_tensor[1] = q;

      ON_CALL(*fe_mock_ptr, ShapeGradient(i, q))
          .WillByDefault(Return(gradient_tensor));
    }
  }

  // Cross-section data for fake two-group, with one material (id = 0)
  std::array<double, 4> sigma_s_values{0.25, 0.25, 0.25, 0.5}; // (i*j + 1)/4
  dealii::FullMatrix<double> sigma_s_matrix{2,2, sigma_s_values.begin()};
  std::unordered_map<int, std::vector<double>> sigma_t{{0, {1.0, 2.0}}}; // i + 1
  std::unordered_map<int, dealii::FullMatrix<double>> sigma_s{{0, sigma_s_matrix}};

  ON_CALL(mock_material, GetSigT())
      .WillByDefault(Return(sigma_t));
  ON_CALL(mock_material, GetSigS())
      .WillByDefault(Return(sigma_s));
  ON_CALL(mock_material, GetDiffusionCoef())
      .WillByDefault(Return(sigma_t));

  cross_sections_ptr = std::make_shared<data::CrossSections>(mock_material);
}

AssertionResult CompareMatrices(const dealii::FullMatrix<double>& expected,
                                const dealii::FullMatrix<double>& result,
                                const double tol = 1e-6) {
  unsigned int rows = expected.m();
  unsigned int cols = expected.n();

  if (result.m() != rows)
    return AssertionFailure() << "Result has wrong number of rows: "
                              << result.m() << ", expected" << rows;
  if (result.n() != cols)
    return AssertionFailure() << "Result has wrong number of columns: "
                              << result.n() << ", expected" << cols;

  for (unsigned int i = 0; i < rows; ++i) {
    for (unsigned int j = 0; j < cols; ++j) {
      if (abs(result(i, j) - expected(i, j)) > tol) {
        return AssertionFailure() << "Entry (" << i << ", " << j <<
                                  ") has value: " << result(i, j) <<
                                  ", expected: " << expected(i, j);
      }
    }
  }
  return AssertionSuccess();
}

TEST_F(FormulationCFEMDiffusionTest, ConstructorTest) {
  EXPECT_CALL(*fe_mock_ptr, dofs_per_cell())
      .WillOnce(DoDefault());
  EXPECT_CALL(*fe_mock_ptr, n_cell_quad_pts())
      .WillOnce(DoDefault());
  EXPECT_CALL(*fe_mock_ptr, n_face_quad_pts())
      .WillOnce(DoDefault());

  formulation::scalar::CFEM_Diffusion<2> test_diffusion(fe_mock_ptr,
                                                        cross_sections_ptr);

  EXPECT_EQ(fe_mock_ptr.use_count(), 2);
  EXPECT_EQ(cross_sections_ptr.use_count(), 2);
}

TEST_F(FormulationCFEMDiffusionTest, PrecalculateTest) {
  // Shape call, by default, returns (quadrature point index + degree of freedom)
  // Gradient call will return a tensor of [i, q]
  // Expected results, we need to make arrays to put them into dealii matrices
  std::array<double, 4> shape_matrix_q_0_values = {0, 0,
                                                   0, 1};
  std::array<double, 4> shape_matrix_q_1_values = {1, 2,
                                                   2, 4};
  std::array<double, 4> gradient_matrix_q_0_values = {0, 0,
                                                      0, 1};
  std::array<double, 4> gradient_matrix_q_1_values = {1, 1,
                                                      1, 2};

  dealii::FullMatrix<double> shape_matrix_q_0{2,2,
                                              shape_matrix_q_0_values.begin()};
  dealii::FullMatrix<double> shape_matrix_q_1{2,2,
                                              shape_matrix_q_1_values.begin()};
  dealii::FullMatrix<double> gradient_matrix_q_0{2,2,
                                                 gradient_matrix_q_0_values.begin()};
  dealii::FullMatrix<double> gradient_matrix_q_1{2,2,
                                                 gradient_matrix_q_1_values.begin()};

  formulation::scalar::CFEM_Diffusion<2> test_diffusion(fe_mock_ptr,
                                                        cross_sections_ptr);
  dealii::DoFHandler<2>::active_cell_iterator it;

  // Set call expectations
  EXPECT_CALL(*fe_mock_ptr, SetCell(_))
      .Times(1);
  EXPECT_CALL(*fe_mock_ptr, ShapeValue(_,_))
      .Times(16)
      .WillRepeatedly(DoDefault());
  EXPECT_CALL(*fe_mock_ptr, ShapeGradient(_,_))
      .Times(16)
      .WillRepeatedly(DoDefault());

  test_diffusion.Precalculate(it);
  auto shape_squared = test_diffusion.GetShapeSquared();
  auto gradient_squared = test_diffusion.GetGradientSquared();

  EXPECT_TRUE(CompareMatrices(shape_matrix_q_0, shape_squared.at(0)));
  EXPECT_TRUE(CompareMatrices(shape_matrix_q_1, shape_squared.at(1)));
  EXPECT_TRUE(CompareMatrices(gradient_matrix_q_0, gradient_squared.at(0)));
  EXPECT_TRUE(CompareMatrices(gradient_matrix_q_1, gradient_squared.at(1)));
}

TEST_F(FormulationCFEMDiffusionTest, FillCellStreamingTermTest) {
  dealii::FullMatrix<double> test_matrix(2,2);
  dealii::DoFHandler<2>::active_cell_iterator it;

  std::array<double, 4> expected_values{6, 6,
                                        6, 15};
  dealii::FullMatrix<double> expected_matrix(2, 2, expected_values.begin());

  formulation::scalar::CFEM_Diffusion<2> test_diffusion(fe_mock_ptr,
                                                        cross_sections_ptr);

  auto init_token = test_diffusion.Precalculate(it);

  EXPECT_CALL(*fe_mock_ptr, Jacobian(_))
      .Times(2)
      .WillRepeatedly(DoDefault());
  EXPECT_CALL(*fe_mock_ptr, SetCell(it))
      .Times(1);

  test_diffusion.FillCellStreamingTerm(test_matrix, init_token, it, 0, 0);

  EXPECT_TRUE(CompareMatrices(expected_matrix, test_matrix));
}

TEST_F(FormulationCFEMDiffusionTest, FillCellCollisionTermTest) {
  dealii::FullMatrix<double> test_matrix(2,2);
  dealii::DoFHandler<2>::active_cell_iterator it;

  std::array<double, 4> expected_values{4.5, 9.0,
                                        9.0, 20.25};
  dealii::FullMatrix<double> expected_matrix(2, 2, expected_values.begin());

  formulation::scalar::CFEM_Diffusion<2> test_diffusion(fe_mock_ptr,
                                                        cross_sections_ptr);

  auto init_token = test_diffusion.Precalculate(it);

  EXPECT_CALL(*fe_mock_ptr, Jacobian(_))
      .Times(2)
      .WillRepeatedly(DoDefault());
  EXPECT_CALL(*fe_mock_ptr, SetCell(it))
      .Times(1);

  test_diffusion.FillCellCollisionTerm(test_matrix, init_token, it, 0, 0);

  EXPECT_TRUE(CompareMatrices(expected_matrix, test_matrix));
}

} // namespace<commit_msg>added test for FillBoundaryTerm<commit_after>#include "formulation/scalar/cfem_diffusion.h"

#include <array>
#include <memory>
#include <cstdlib>

#include "data/cross_sections.h"
#include "domain/tests/finite_element_mock.h"
#include "material/tests/mock_material.h"
#include "test_helpers/gmock_wrapper.h"
#include "test_helpers/test_helper_functions.h"

namespace {

using ::testing::AssertionResult;
using ::testing::AssertionFailure;
using ::testing::AssertionSuccess;
using ::testing::Le;
using ::testing::Ge;
using ::testing::DoDefault;
using ::testing::NiceMock;
using ::testing::Return;
using ::testing::_;
using namespace bart;

class FormulationCFEMDiffusionTest : public ::testing::Test {
 protected:
  using Matrix = dealii::FullMatrix<double>;
  std::shared_ptr<domain::FiniteElementMock<2>> fe_mock_ptr;
  std::shared_ptr<data::CrossSections> cross_sections_ptr;

  void SetUp() override;
};

void FormulationCFEMDiffusionTest::SetUp() {
  // Make mock objects. Cross-sections is a struct that cannot be mocked, but
  // we can mock the material object it is based on.
  NiceMock<btest::MockMaterial> mock_material;
  fe_mock_ptr = std::make_shared<NiceMock<domain::FiniteElementMock<2>>>();

  ON_CALL(*fe_mock_ptr, dofs_per_cell())
      .WillByDefault(Return(2));
  ON_CALL(*fe_mock_ptr, n_cell_quad_pts())
      .WillByDefault(Return(2));
  ON_CALL(*fe_mock_ptr, n_face_quad_pts())
      .WillByDefault(Return(2));

  for (int q = 0; q < 2; ++q) {
    ON_CALL(*fe_mock_ptr, Jacobian(q))
        .WillByDefault(Return((1 + q)*3));
    for (int i = 0; i < 2; ++i) {
      ON_CALL(*fe_mock_ptr, ShapeValue(i, q))
          .WillByDefault(Return(i + q));

      dealii::Tensor<1, 2> gradient_tensor;
      gradient_tensor[0] = i;
      gradient_tensor[1] = q;

      ON_CALL(*fe_mock_ptr, ShapeGradient(i, q))
          .WillByDefault(Return(gradient_tensor));
    }
  }

  // Cross-section data for fake two-group, with one material (id = 0)
  std::array<double, 4> sigma_s_values{0.25, 0.25, 0.25, 0.5}; // (i*j + 1)/4
  dealii::FullMatrix<double> sigma_s_matrix{2,2, sigma_s_values.begin()};
  std::unordered_map<int, std::vector<double>> sigma_t{{0, {1.0, 2.0}}}; // i + 1
  std::unordered_map<int, dealii::FullMatrix<double>> sigma_s{{0, sigma_s_matrix}};

  ON_CALL(mock_material, GetSigT())
      .WillByDefault(Return(sigma_t));
  ON_CALL(mock_material, GetSigS())
      .WillByDefault(Return(sigma_s));
  ON_CALL(mock_material, GetDiffusionCoef())
      .WillByDefault(Return(sigma_t));

  cross_sections_ptr = std::make_shared<data::CrossSections>(mock_material);
}

AssertionResult CompareMatrices(const dealii::FullMatrix<double>& expected,
                                const dealii::FullMatrix<double>& result,
                                const double tol = 1e-6) {
  unsigned int rows = expected.m();
  unsigned int cols = expected.n();

  if (result.m() != rows)
    return AssertionFailure() << "Result has wrong number of rows: "
                              << result.m() << ", expected" << rows;
  if (result.n() != cols)
    return AssertionFailure() << "Result has wrong number of columns: "
                              << result.n() << ", expected" << cols;

  for (unsigned int i = 0; i < rows; ++i) {
    for (unsigned int j = 0; j < cols; ++j) {
      if (abs(result(i, j) - expected(i, j)) > tol) {
        return AssertionFailure() << "Entry (" << i << ", " << j <<
                                  ") has value: " << result(i, j) <<
                                  ", expected: " << expected(i, j);
      }
    }
  }
  return AssertionSuccess();
}

TEST_F(FormulationCFEMDiffusionTest, ConstructorTest) {
  EXPECT_CALL(*fe_mock_ptr, dofs_per_cell())
      .WillOnce(DoDefault());
  EXPECT_CALL(*fe_mock_ptr, n_cell_quad_pts())
      .WillOnce(DoDefault());
  EXPECT_CALL(*fe_mock_ptr, n_face_quad_pts())
      .WillOnce(DoDefault());

  formulation::scalar::CFEM_Diffusion<2> test_diffusion(fe_mock_ptr,
                                                        cross_sections_ptr);

  EXPECT_EQ(fe_mock_ptr.use_count(), 2);
  EXPECT_EQ(cross_sections_ptr.use_count(), 2);
}

TEST_F(FormulationCFEMDiffusionTest, PrecalculateTest) {
  // Shape call, by default, returns (quadrature point index + degree of freedom)
  // Gradient call will return a tensor of [i, q]
  // Expected results, we need to make arrays to put them into dealii matrices
  std::array<double, 4> shape_matrix_q_0_values = {0, 0,
                                                   0, 1};
  std::array<double, 4> shape_matrix_q_1_values = {1, 2,
                                                   2, 4};
  std::array<double, 4> gradient_matrix_q_0_values = {0, 0,
                                                      0, 1};
  std::array<double, 4> gradient_matrix_q_1_values = {1, 1,
                                                      1, 2};

  dealii::FullMatrix<double> shape_matrix_q_0{2,2,
                                              shape_matrix_q_0_values.begin()};
  dealii::FullMatrix<double> shape_matrix_q_1{2,2,
                                              shape_matrix_q_1_values.begin()};
  dealii::FullMatrix<double> gradient_matrix_q_0{2,2,
                                                 gradient_matrix_q_0_values.begin()};
  dealii::FullMatrix<double> gradient_matrix_q_1{2,2,
                                                 gradient_matrix_q_1_values.begin()};

  formulation::scalar::CFEM_Diffusion<2> test_diffusion(fe_mock_ptr,
                                                        cross_sections_ptr);
  dealii::DoFHandler<2>::active_cell_iterator it;

  // Set call expectations
  EXPECT_CALL(*fe_mock_ptr, SetCell(_))
      .Times(1);
  EXPECT_CALL(*fe_mock_ptr, ShapeValue(_,_))
      .Times(16)
      .WillRepeatedly(DoDefault());
  EXPECT_CALL(*fe_mock_ptr, ShapeGradient(_,_))
      .Times(16)
      .WillRepeatedly(DoDefault());

  test_diffusion.Precalculate(it);
  auto shape_squared = test_diffusion.GetShapeSquared();
  auto gradient_squared = test_diffusion.GetGradientSquared();

  EXPECT_TRUE(CompareMatrices(shape_matrix_q_0, shape_squared.at(0)));
  EXPECT_TRUE(CompareMatrices(shape_matrix_q_1, shape_squared.at(1)));
  EXPECT_TRUE(CompareMatrices(gradient_matrix_q_0, gradient_squared.at(0)));
  EXPECT_TRUE(CompareMatrices(gradient_matrix_q_1, gradient_squared.at(1)));
}

TEST_F(FormulationCFEMDiffusionTest, FillCellStreamingTermTest) {
  dealii::FullMatrix<double> test_matrix(2,2);
  dealii::DoFHandler<2>::active_cell_iterator it;

  std::array<double, 4> expected_values{6, 6,
                                        6, 15};
  dealii::FullMatrix<double> expected_matrix(2, 2, expected_values.begin());

  formulation::scalar::CFEM_Diffusion<2> test_diffusion(fe_mock_ptr,
                                                        cross_sections_ptr);

  auto init_token = test_diffusion.Precalculate(it);

  EXPECT_CALL(*fe_mock_ptr, Jacobian(_))
      .Times(2)
      .WillRepeatedly(DoDefault());
  EXPECT_CALL(*fe_mock_ptr, SetCell(it))
      .Times(1);

  test_diffusion.FillCellStreamingTerm(test_matrix, init_token, it, 0, 0);

  EXPECT_TRUE(CompareMatrices(expected_matrix, test_matrix));
}

TEST_F(FormulationCFEMDiffusionTest, FillCellCollisionTermTest) {
  dealii::FullMatrix<double> test_matrix(2,2);
  dealii::DoFHandler<2>::active_cell_iterator it;

  std::array<double, 4> expected_values{4.5, 9.0,
                                        9.0, 20.25};
  dealii::FullMatrix<double> expected_matrix(2, 2, expected_values.begin());

  formulation::scalar::CFEM_Diffusion<2> test_diffusion(fe_mock_ptr,
                                                        cross_sections_ptr);

  auto init_token = test_diffusion.Precalculate(it);

  EXPECT_CALL(*fe_mock_ptr, Jacobian(_))
      .Times(2)
      .WillRepeatedly(DoDefault());
  EXPECT_CALL(*fe_mock_ptr, SetCell(it))
      .Times(1);

  test_diffusion.FillCellCollisionTerm(test_matrix, init_token, it, 0, 0);

  EXPECT_TRUE(CompareMatrices(expected_matrix, test_matrix));
}

TEST_F(FormulationCFEMDiffusionTest, FillBoundaryTermTestReflective) {
  dealii::FullMatrix<double> test_matrix(2,2);
  dealii::FullMatrix<double> expected_matrix(2,2);
  dealii::DoFHandler<2>::active_cell_iterator cell;
  auto boundary = formulation::scalar::CFEM_Diffusion<2>::BoundaryType::kReflective;

  formulation::scalar::CFEM_Diffusion<2> test_diffusion(fe_mock_ptr,
                                                        cross_sections_ptr);

  test_diffusion.FillBoundaryTerm(test_matrix, cell, 0, 0, boundary);

  EXPECT_TRUE(CompareMatrices(expected_matrix, test_matrix));
}

TEST_F(FormulationCFEMDiffusionTest, FillBoundaryTermTestVacuum) {
  dealii::FullMatrix<double> test_matrix(2,2);
  dealii::DoFHandler<2>::active_cell_iterator cell;
  auto boundary = formulation::scalar::CFEM_Diffusion<2>::BoundaryType::kVacuum;

  std::array<double, 4> expected_values{3, 6,
                                        6, 13.5};
  dealii::FullMatrix<double> expected_matrix(2, 2, expected_values.begin());

  formulation::scalar::CFEM_Diffusion<2> test_diffusion(fe_mock_ptr,
                                                        cross_sections_ptr);

  EXPECT_CALL(*fe_mock_ptr, SetFace(cell, 0))
      .Times(1);
  EXPECT_CALL(*fe_mock_ptr, Jacobian(_))
      .Times(2)
      .WillRepeatedly(DoDefault());

  test_diffusion.FillBoundaryTerm(test_matrix, cell, 0, 0, boundary);

  EXPECT_TRUE(CompareMatrices(expected_matrix, test_matrix));

}

} // namespace<|endoftext|>