<commit_before>// This file is a part of the IncludeOS unikernel - www.includeos.org
//
// Copyright 2015 Oslo and Akershus University College of Applied Sciences
// and Alfred Bratterud
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#include <os>
#include <profile>
#include <timers>
#define USE_STACK_SAMPLING

#include "ircd.hpp"
static IrcServer* ircd;

void Service::start(const std::string&)
{
  auto& inet = net::Inet4::ifconfig<>(10);
  inet.network_config(
      {  10, 0,  0, 42 },  // IP
      { 255,255,255, 0 },  // Netmask
      {  10, 0,  0,  1 },  // Gateway
      {  10, 0,  0,  1 }); // DNS

  // IRC default port
  static std::vector<std::string> motd;
  motd.push_back("Welcome to the");
  motd.push_back("IncludeOS IRC server");
  motd.push_back("-§- 4Head -§-");

  ircd =
  new IrcServer(inet, 6667, "irc.includeos.org", "IncludeNet",
  [] () -> const std::vector<std::string>& {
    return motd;
  });
}

#include <ctime>
std::string now()
{
  auto  tnow = time(0);
  auto* curtime = localtime(&tnow);

  char buff[48];
  int len = strftime(buff, sizeof(buff), "%c", curtime);
  return std::string(buff, len);
}

#ifdef USE_STACK_SAMPLING
// print N results to stdout
void ssampler_print(int N)
{
  auto samp = StackSampler::results(N);
  int total = StackSampler::samples_total();

  printf("Stack sampling - %d results (%u samples)\n",
         samp.size(), total);
  for (auto& sa : samp)
  {
    // percentage of total samples
    float perc = sa.samp / (float)total * 100.0f;
    printf("%5.2f%%  %*u: %s\n",
           perc, 8, sa.samp, sa.name.c_str());
  }
}
#endif

#define PERIOD_SECS    2

void print_stats(uint32_t)
{
#ifdef USE_STACK_SAMPLING
  StackSampler::set_mask(true);
#endif

  static std::vector<int> M;
  static int last = 0;
  // only keep 5 measurements
  if (M.size() > 4) M.erase(M.begin());

  int diff = ircd->get_counter(STAT_TOTAL_CONNS) - last;
  last = ircd->get_counter(STAT_TOTAL_CONNS);
  // @PERIOD_SECS between measurements
  M.push_back(diff / PERIOD_SECS);

  double cps = 0.0;
  for (int C : M) cps += C;
  cps /= M.size();

  printf("[%s] Conns/sec %.1f  Heap %.1f kb\n",
      now().c_str(), cps, OS::heap_usage() / 1024.f);
  // client and channel stats
  printf("Conns: %u  Clis: %u  Club: %u  Chans: %u\n",
         ircd->get_counter(STAT_TOTAL_CONNS), ircd->get_counter(STAT_LOCAL_USERS),
         ircd->club(), ircd->get_counter(STAT_CHANNELS));
  printf("*** ---------------------- ***\n");
#ifdef USE_STACK_SAMPLING
  // stack sampler results
  ssampler_print(20);
  printf("*** ---------------------- ***\n");
#endif
  // heap statistics
  print_heap_info();
  printf("*** ---------------------- ***\n");

#ifdef USE_STACK_SAMPLING
  StackSampler::set_mask(false);
#endif
}

void Service::ready()
{
  printf("*** IRC SERVICE STARTED ***\n");
#ifdef USE_STACK_SAMPLING
  StackSampler::begin();
#endif

  using namespace std::chrono;
  Timers::periodic(seconds(1), seconds(PERIOD_SECS), print_stats);
}
<commit_msg>Use caller stack sampling mode<commit_after>// This file is a part of the IncludeOS unikernel - www.includeos.org
//
// Copyright 2015 Oslo and Akershus University College of Applied Sciences
// and Alfred Bratterud
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#include <os>
#include <profile>
#include <timers>
#define USE_STACK_SAMPLING

#include "ircd.hpp"
static IrcServer* ircd;

// prevent default serial out
void add_default_stdout_handlers() {}
#include <hw/serial.hpp>

void Service::start(const std::string&)
{
  // add own serial out after service start
  auto& com1 = hw::Serial::port<1>();
  OS::add_standard_out(com1.get_rsprint_handler());
  // show that we are starting :)
  printf("*** IRC Service starting up...\n");

  // default configuration (with DHCP)
  auto& inet = net::Inet4::ifconfig<>(10);
  inet.network_config(
      {  10, 0,  0, 42 },  // IP
      { 255,255,255, 0 },  // Netmask
      {  10, 0,  0,  1 },  // Gateway
      {  10, 0,  0,  1 }); // DNS

  // IRC default port
  static std::vector<std::string> motd;
  motd.push_back("Welcome to the");
  motd.push_back("IncludeOS IRC server");
  motd.push_back("-§- 4Head -§-");

  ircd =
  new IrcServer(inet, 6667, "irc.includeos.org", "IncludeNet",
  [] () -> const std::vector<std::string>& {
    return motd;
  });
}

#include <ctime>
std::string now()
{
  auto  tnow = time(0);
  auto* curtime = localtime(&tnow);

  char buff[48];
  int len = strftime(buff, sizeof(buff), "%c", curtime);
  return std::string(buff, len);
}

#ifdef USE_STACK_SAMPLING
// print N results to stdout
void ssampler_print(int N)
{
  auto samp = StackSampler::results(N);
  int total = StackSampler::samples_total();

  printf("Stack sampling - %d results (%u samples)\n",
         samp.size(), total);
  for (auto& sa : samp)
  {
    // percentage of total samples
    float perc = sa.samp / (float)total * 100.0f;
    printf("%5.2f%%  %*u: %s\n",
           perc, 8, sa.samp, sa.name.c_str());
  }
}
#endif

#define PERIOD_SECS    2

void print_stats(uint32_t)
{
#ifdef USE_STACK_SAMPLING
  StackSampler::set_mask(true);
#endif

  static std::vector<int> M;
  static int last = 0;
  // only keep 5 measurements
  if (M.size() > 4) M.erase(M.begin());

  int diff = ircd->get_counter(STAT_TOTAL_CONNS) - last;
  last = ircd->get_counter(STAT_TOTAL_CONNS);
  // @PERIOD_SECS between measurements
  M.push_back(diff / PERIOD_SECS);

  double cps = 0.0;
  for (int C : M) cps += C;
  cps /= M.size();

  printf("[%s] Conns/sec %.1f  Heap %.1f kb\n",
      now().c_str(), cps, OS::heap_usage() / 1024.f);
  // client and channel stats
  printf("Conns: %u  Clis: %u  Club: %u  Chans: %u\n",
         ircd->get_counter(STAT_TOTAL_CONNS), ircd->get_counter(STAT_LOCAL_USERS),
         ircd->club(), ircd->get_counter(STAT_CHANNELS));
  printf("*** ---------------------- ***\n");
#ifdef USE_STACK_SAMPLING
  // stack sampler results
  ssampler_print(20);
  printf("*** ---------------------- ***\n");
#endif
  // heap statistics
  print_heap_info();
  printf("*** ---------------------- ***\n");

#ifdef USE_STACK_SAMPLING
  StackSampler::set_mask(false);
#endif
}

void Service::ready()
{
  printf("*** IRC SERVICE STARTED ***\n");
#ifdef USE_STACK_SAMPLING
  StackSampler::begin();
  StackSampler::set_mode(StackSampler::MODE_CALLER);
#endif

  using namespace std::chrono;
  Timers::periodic(seconds(1), seconds(PERIOD_SECS), print_stats);
}
<|endoftext|>


<commit_before>/*
 * Copyright © 2010 Intel Corporation
 *
 * Permission is hereby granted, free of charge, to any person obtaining a
 * copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation
 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
 * and/or sell copies of the Software, and to permit persons to whom the
 * Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice (including the next
 * paragraph) shall be included in all copies or substantial portions of the
 * Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
 * DEALINGS IN THE SOFTWARE.
 */

/**
 * \file opt_array_splitting.cpp
 *
 * If an array is always dereferenced with a constant index, then
 * split it apart into its elements, making it more amenable to other
 * optimization passes.
 *
 * This skips uniform/varying arrays, which would need careful
 * handling due to their ir->location fields tying them to the GL API
 * and other shader stages.
 */

#include "ir.h"
#include "ir_visitor.h"
#include "ir_rvalue_visitor.h"
#include "glsl_types.h"

static bool debug = false;

namespace {

namespace opt_array_splitting {

class variable_entry : public exec_node
{
public:
   variable_entry(ir_variable *var)
   {
      this->var = var;
      this->split = true;
      this->declaration = false;
      this->components = NULL;
      this->mem_ctx = NULL;
      if (var->type->is_array())
	 this->size = var->type->length;
      else
	 this->size = var->type->matrix_columns;
   }

   ir_variable *var; /* The key: the variable's pointer. */
   unsigned size; /* array length or matrix columns */

   /** Whether this array should be split or not. */
   bool split;

   /* If the variable had a decl we can work with in the instruction
    * stream.  We can't do splitting on function arguments, which
    * don't get this variable set.
    */
   bool declaration;

   ir_variable **components;

   /** ralloc_parent(this->var) -- the shader's talloc context. */
   void *mem_ctx;
};

} /* namespace */

using namespace opt_array_splitting;

/**
 * This class does a walk over the tree, coming up with the set of
 * variables that could be split by looking to see if they are arrays
 * that are only ever constant-index dereferenced.
 */
class ir_array_reference_visitor : public ir_hierarchical_visitor {
public:
   ir_array_reference_visitor(void)
   {
      this->mem_ctx = ralloc_context(NULL);
      this->variable_list.make_empty();
   }

   ~ir_array_reference_visitor(void)
   {
      ralloc_free(mem_ctx);
   }

   bool get_split_list(exec_list *instructions, bool linked);

   virtual ir_visitor_status visit(ir_variable *);
   virtual ir_visitor_status visit(ir_dereference_variable *);
   virtual ir_visitor_status visit_enter(ir_dereference_array *);
   virtual ir_visitor_status visit_enter(ir_function_signature *);

   variable_entry *get_variable_entry(ir_variable *var);

   /* List of variable_entry */
   exec_list variable_list;

   void *mem_ctx;
};

} /* namespace */

variable_entry *
ir_array_reference_visitor::get_variable_entry(ir_variable *var)
{
   assert(var);

   if (var->data.mode != ir_var_auto &&
       var->data.mode != ir_var_temporary)
      return NULL;

   if (!(var->type->is_array() || var->type->is_matrix()))
      return NULL;

   /* If the array hasn't been sized yet, we can't split it.  After
    * linking, this should be resolved.
    */
   if (var->type->is_unsized_array())
      return NULL;

   foreach_in_list(variable_entry, entry, &this->variable_list) {
      if (entry->var == var)
	 return entry;
   }

   variable_entry *entry = new(mem_ctx) variable_entry(var);
   this->variable_list.push_tail(entry);
   return entry;
}

ir_visitor_status
ir_array_reference_visitor::visit(ir_variable *ir)
{
   variable_entry *entry = this->get_variable_entry(ir);

   if (entry)
      entry->declaration = true;

   return visit_continue;
}

ir_visitor_status
ir_array_reference_visitor::visit(ir_dereference_variable *ir)
{
   variable_entry *entry = this->get_variable_entry(ir->var);

   /* If we made it to here without seeing an ir_dereference_array,
    * then the dereference of this array didn't have a constant index
    * (see the visit_continue_with_parent below), so we can't split
    * the variable.
    */
   if (entry)
      entry->split = false;

   return visit_continue;
}

ir_visitor_status
ir_array_reference_visitor::visit_enter(ir_dereference_array *ir)
{
   ir_dereference_variable *deref = ir->array->as_dereference_variable();
   if (!deref)
      return visit_continue;

   variable_entry *entry = this->get_variable_entry(deref->var);

   /* If the access to the array has a variable index, we wouldn't
    * know which split variable this dereference should go to.
    */
   if (entry && !ir->array_index->as_constant())
      entry->split = false;

   return visit_continue_with_parent;
}

ir_visitor_status
ir_array_reference_visitor::visit_enter(ir_function_signature *ir)
{
   /* We don't have logic for array-splitting function arguments,
    * so just look at the body instructions and not the parameter
    * declarations.
    */
   visit_list_elements(this, &ir->body);
   return visit_continue_with_parent;
}

bool
ir_array_reference_visitor::get_split_list(exec_list *instructions,
					   bool linked)
{
   visit_list_elements(this, instructions);

   /* If the shaders aren't linked yet, we can't mess with global
    * declarations, which need to be matched by name across shaders.
    */
   if (!linked) {
      foreach_in_list(ir_instruction, node, instructions) {
	 ir_variable *var = node->as_variable();
	 if (var) {
	    variable_entry *entry = get_variable_entry(var);
	    if (entry)
	       entry->remove();
	 }
      }
   }

   /* Trim out variables we found that we can't split. */
   foreach_in_list_safe(variable_entry, entry, &variable_list) {
      if (debug) {
	 printf("array %s@%p: decl %d, split %d\n",
		entry->var->name, (void *) entry->var, entry->declaration,
		entry->split);
      }

      if (!(entry->declaration && entry->split)) {
	 entry->remove();
      }
   }

   return !variable_list.is_empty();
}

/**
 * This class rewrites the dereferences of arrays that have been split
 * to use the newly created ir_variables for each component.
 */
class ir_array_splitting_visitor : public ir_rvalue_visitor {
public:
   ir_array_splitting_visitor(exec_list *vars)
   {
      this->variable_list = vars;
   }

   virtual ~ir_array_splitting_visitor()
   {
   }

   virtual ir_visitor_status visit_leave(ir_assignment *);

   void split_deref(ir_dereference **deref);
   void handle_rvalue(ir_rvalue **rvalue);
   variable_entry *get_splitting_entry(ir_variable *var);

   exec_list *variable_list;
};

variable_entry *
ir_array_splitting_visitor::get_splitting_entry(ir_variable *var)
{
   assert(var);

   foreach_in_list(variable_entry, entry, this->variable_list) {
      if (entry->var == var) {
	 return entry;
      }
   }

   return NULL;
}

void
ir_array_splitting_visitor::split_deref(ir_dereference **deref)
{
   ir_dereference_array *deref_array = (*deref)->as_dereference_array();
   if (!deref_array)
      return;

   ir_dereference_variable *deref_var = deref_array->array->as_dereference_variable();
   if (!deref_var)
      return;
   ir_variable *var = deref_var->var;

   variable_entry *entry = get_splitting_entry(var);
   if (!entry)
      return;

   ir_constant *constant = deref_array->array_index->as_constant();
   assert(constant);

   if (constant->value.i[0] >= 0 && constant->value.i[0] < (int)entry->size) {
      *deref = new(entry->mem_ctx)
	 ir_dereference_variable(entry->components[constant->value.i[0]]);
   } else {
      /* There was a constant array access beyond the end of the
       * array.  This might have happened due to constant folding
       * after the initial parse.  This produces an undefined value,
       * but shouldn't crash.  Just give them an uninitialized
       * variable.
       */
      ir_variable *temp = new(entry->mem_ctx) ir_variable(deref_array->type,
							  "undef",
							  ir_var_temporary);
      entry->components[0]->insert_before(temp);
      *deref = new(entry->mem_ctx) ir_dereference_variable(temp);
   }
}

void
ir_array_splitting_visitor::handle_rvalue(ir_rvalue **rvalue)
{
   if (!*rvalue)
      return;

   ir_dereference *deref = (*rvalue)->as_dereference();

   if (!deref)
      return;

   split_deref(&deref);
   *rvalue = deref;
}

ir_visitor_status
ir_array_splitting_visitor::visit_leave(ir_assignment *ir)
{
   /* The normal rvalue visitor skips the LHS of assignments, but we
    * need to process those just the same.
    */
   ir_rvalue *lhs = ir->lhs;

   handle_rvalue(&lhs);
   ir->lhs = lhs->as_dereference();

   ir->lhs->accept(this);

   handle_rvalue(&ir->rhs);
   ir->rhs->accept(this);

   if (ir->condition) {
      handle_rvalue(&ir->condition);
      ir->condition->accept(this);
   }

   return visit_continue;
}

bool
optimize_split_arrays(exec_list *instructions, bool linked)
{
   ir_array_reference_visitor refs;
   if (!refs.get_split_list(instructions, linked))
      return false;

   void *mem_ctx = ralloc_context(NULL);

   /* Replace the decls of the arrays to be split with their split
    * components.
    */
   foreach_in_list(variable_entry, entry, &refs.variable_list) {
      const struct glsl_type *type = entry->var->type;
      const struct glsl_type *subtype;

      if (type->is_matrix())
	 subtype = type->column_type();
      else
	 subtype = type->fields.array;

      entry->mem_ctx = ralloc_parent(entry->var);

      entry->components = ralloc_array(mem_ctx,
				       ir_variable *,
				       entry->size);

      for (unsigned int i = 0; i < entry->size; i++) {
	 const char *name = ralloc_asprintf(mem_ctx, "%s_%d",
					    entry->var->name, i);

	 entry->components[i] =
	    new(entry->mem_ctx) ir_variable(subtype, name, ir_var_temporary);
	 entry->var->insert_before(entry->components[i]);
      }

      entry->var->remove();
   }

   ir_array_splitting_visitor split(&refs.variable_list);
   visit_list_elements(&split, instructions);

   if (debug)
      _mesa_print_ir(stdout, instructions, NULL);

   ralloc_free(mem_ctx);

   return true;

}
<commit_msg>glsl: handle case where index is array deref in optimize_split_arrays<commit_after>/*
 * Copyright © 2010 Intel Corporation
 *
 * Permission is hereby granted, free of charge, to any person obtaining a
 * copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation
 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
 * and/or sell copies of the Software, and to permit persons to whom the
 * Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice (including the next
 * paragraph) shall be included in all copies or substantial portions of the
 * Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
 * DEALINGS IN THE SOFTWARE.
 */

/**
 * \file opt_array_splitting.cpp
 *
 * If an array is always dereferenced with a constant index, then
 * split it apart into its elements, making it more amenable to other
 * optimization passes.
 *
 * This skips uniform/varying arrays, which would need careful
 * handling due to their ir->location fields tying them to the GL API
 * and other shader stages.
 */

#include "ir.h"
#include "ir_visitor.h"
#include "ir_rvalue_visitor.h"
#include "glsl_types.h"

static bool debug = false;

namespace {

namespace opt_array_splitting {

class variable_entry : public exec_node
{
public:
   variable_entry(ir_variable *var)
   {
      this->var = var;
      this->split = true;
      this->declaration = false;
      this->components = NULL;
      this->mem_ctx = NULL;
      if (var->type->is_array())
	 this->size = var->type->length;
      else
	 this->size = var->type->matrix_columns;
   }

   ir_variable *var; /* The key: the variable's pointer. */
   unsigned size; /* array length or matrix columns */

   /** Whether this array should be split or not. */
   bool split;

   /* If the variable had a decl we can work with in the instruction
    * stream.  We can't do splitting on function arguments, which
    * don't get this variable set.
    */
   bool declaration;

   ir_variable **components;

   /** ralloc_parent(this->var) -- the shader's talloc context. */
   void *mem_ctx;
};

} /* namespace */

using namespace opt_array_splitting;

/**
 * This class does a walk over the tree, coming up with the set of
 * variables that could be split by looking to see if they are arrays
 * that are only ever constant-index dereferenced.
 */
class ir_array_reference_visitor : public ir_hierarchical_visitor {
public:
   ir_array_reference_visitor(void)
   {
      this->mem_ctx = ralloc_context(NULL);
      this->variable_list.make_empty();
   }

   ~ir_array_reference_visitor(void)
   {
      ralloc_free(mem_ctx);
   }

   bool get_split_list(exec_list *instructions, bool linked);

   virtual ir_visitor_status visit(ir_variable *);
   virtual ir_visitor_status visit(ir_dereference_variable *);
   virtual ir_visitor_status visit_enter(ir_dereference_array *);
   virtual ir_visitor_status visit_enter(ir_function_signature *);

   variable_entry *get_variable_entry(ir_variable *var);

   /* List of variable_entry */
   exec_list variable_list;

   void *mem_ctx;
};

} /* namespace */

variable_entry *
ir_array_reference_visitor::get_variable_entry(ir_variable *var)
{
   assert(var);

   if (var->data.mode != ir_var_auto &&
       var->data.mode != ir_var_temporary)
      return NULL;

   if (!(var->type->is_array() || var->type->is_matrix()))
      return NULL;

   /* If the array hasn't been sized yet, we can't split it.  After
    * linking, this should be resolved.
    */
   if (var->type->is_unsized_array())
      return NULL;

   foreach_in_list(variable_entry, entry, &this->variable_list) {
      if (entry->var == var)
	 return entry;
   }

   variable_entry *entry = new(mem_ctx) variable_entry(var);
   this->variable_list.push_tail(entry);
   return entry;
}

ir_visitor_status
ir_array_reference_visitor::visit(ir_variable *ir)
{
   variable_entry *entry = this->get_variable_entry(ir);

   if (entry)
      entry->declaration = true;

   return visit_continue;
}

ir_visitor_status
ir_array_reference_visitor::visit(ir_dereference_variable *ir)
{
   variable_entry *entry = this->get_variable_entry(ir->var);

   /* If we made it to here without seeing an ir_dereference_array,
    * then the dereference of this array didn't have a constant index
    * (see the visit_continue_with_parent below), so we can't split
    * the variable.
    */
   if (entry)
      entry->split = false;

   return visit_continue;
}

ir_visitor_status
ir_array_reference_visitor::visit_enter(ir_dereference_array *ir)
{
   ir_dereference_variable *deref = ir->array->as_dereference_variable();
   if (!deref)
      return visit_continue;

   variable_entry *entry = this->get_variable_entry(deref->var);

   /* If the access to the array has a variable index, we wouldn't
    * know which split variable this dereference should go to.
    */
   if (entry && !ir->array_index->as_constant())
      entry->split = false;

   /* If the index is also array dereference, visit index. */
   if (ir->array_index->as_dereference_array())
      visit_enter(ir->array_index->as_dereference_array());

   return visit_continue_with_parent;
}

ir_visitor_status
ir_array_reference_visitor::visit_enter(ir_function_signature *ir)
{
   /* We don't have logic for array-splitting function arguments,
    * so just look at the body instructions and not the parameter
    * declarations.
    */
   visit_list_elements(this, &ir->body);
   return visit_continue_with_parent;
}

bool
ir_array_reference_visitor::get_split_list(exec_list *instructions,
					   bool linked)
{
   visit_list_elements(this, instructions);

   /* If the shaders aren't linked yet, we can't mess with global
    * declarations, which need to be matched by name across shaders.
    */
   if (!linked) {
      foreach_in_list(ir_instruction, node, instructions) {
	 ir_variable *var = node->as_variable();
	 if (var) {
	    variable_entry *entry = get_variable_entry(var);
	    if (entry)
	       entry->remove();
	 }
      }
   }

   /* Trim out variables we found that we can't split. */
   foreach_in_list_safe(variable_entry, entry, &variable_list) {
      if (debug) {
	 printf("array %s@%p: decl %d, split %d\n",
		entry->var->name, (void *) entry->var, entry->declaration,
		entry->split);
      }

      if (!(entry->declaration && entry->split)) {
	 entry->remove();
      }
   }

   return !variable_list.is_empty();
}

/**
 * This class rewrites the dereferences of arrays that have been split
 * to use the newly created ir_variables for each component.
 */
class ir_array_splitting_visitor : public ir_rvalue_visitor {
public:
   ir_array_splitting_visitor(exec_list *vars)
   {
      this->variable_list = vars;
   }

   virtual ~ir_array_splitting_visitor()
   {
   }

   virtual ir_visitor_status visit_leave(ir_assignment *);

   void split_deref(ir_dereference **deref);
   void handle_rvalue(ir_rvalue **rvalue);
   variable_entry *get_splitting_entry(ir_variable *var);

   exec_list *variable_list;
};

variable_entry *
ir_array_splitting_visitor::get_splitting_entry(ir_variable *var)
{
   assert(var);

   foreach_in_list(variable_entry, entry, this->variable_list) {
      if (entry->var == var) {
	 return entry;
      }
   }

   return NULL;
}

void
ir_array_splitting_visitor::split_deref(ir_dereference **deref)
{
   ir_dereference_array *deref_array = (*deref)->as_dereference_array();
   if (!deref_array)
      return;

   ir_dereference_variable *deref_var = deref_array->array->as_dereference_variable();
   if (!deref_var)
      return;
   ir_variable *var = deref_var->var;

   variable_entry *entry = get_splitting_entry(var);
   if (!entry)
      return;

   ir_constant *constant = deref_array->array_index->as_constant();
   assert(constant);

   if (constant->value.i[0] >= 0 && constant->value.i[0] < (int)entry->size) {
      *deref = new(entry->mem_ctx)
	 ir_dereference_variable(entry->components[constant->value.i[0]]);
   } else {
      /* There was a constant array access beyond the end of the
       * array.  This might have happened due to constant folding
       * after the initial parse.  This produces an undefined value,
       * but shouldn't crash.  Just give them an uninitialized
       * variable.
       */
      ir_variable *temp = new(entry->mem_ctx) ir_variable(deref_array->type,
							  "undef",
							  ir_var_temporary);
      entry->components[0]->insert_before(temp);
      *deref = new(entry->mem_ctx) ir_dereference_variable(temp);
   }
}

void
ir_array_splitting_visitor::handle_rvalue(ir_rvalue **rvalue)
{
   if (!*rvalue)
      return;

   ir_dereference *deref = (*rvalue)->as_dereference();

   if (!deref)
      return;

   split_deref(&deref);
   *rvalue = deref;
}

ir_visitor_status
ir_array_splitting_visitor::visit_leave(ir_assignment *ir)
{
   /* The normal rvalue visitor skips the LHS of assignments, but we
    * need to process those just the same.
    */
   ir_rvalue *lhs = ir->lhs;

   handle_rvalue(&lhs);
   ir->lhs = lhs->as_dereference();

   ir->lhs->accept(this);

   handle_rvalue(&ir->rhs);
   ir->rhs->accept(this);

   if (ir->condition) {
      handle_rvalue(&ir->condition);
      ir->condition->accept(this);
   }

   return visit_continue;
}

bool
optimize_split_arrays(exec_list *instructions, bool linked)
{
   ir_array_reference_visitor refs;
   if (!refs.get_split_list(instructions, linked))
      return false;

   void *mem_ctx = ralloc_context(NULL);

   /* Replace the decls of the arrays to be split with their split
    * components.
    */
   foreach_in_list(variable_entry, entry, &refs.variable_list) {
      const struct glsl_type *type = entry->var->type;
      const struct glsl_type *subtype;

      if (type->is_matrix())
	 subtype = type->column_type();
      else
	 subtype = type->fields.array;

      entry->mem_ctx = ralloc_parent(entry->var);

      entry->components = ralloc_array(mem_ctx,
				       ir_variable *,
				       entry->size);

      for (unsigned int i = 0; i < entry->size; i++) {
	 const char *name = ralloc_asprintf(mem_ctx, "%s_%d",
					    entry->var->name, i);

	 entry->components[i] =
	    new(entry->mem_ctx) ir_variable(subtype, name, ir_var_temporary);
	 entry->var->insert_before(entry->components[i]);
      }

      entry->var->remove();
   }

   ir_array_splitting_visitor split(&refs.variable_list);
   visit_list_elements(&split, instructions);

   if (debug)
      _mesa_print_ir(stdout, instructions, NULL);

   ralloc_free(mem_ctx);

   return true;

}
<|endoftext|>


<commit_before>/**
 * Unit Tests for Piezas
**/

#include <gtest/gtest.h>
#include "Piezas.h"

class PiezasTest : public ::testing::Test
{
    protected:
        PiezasTest(){} //constructor runs before each test
        virtual ~PiezasTest(){} //destructor cleans up after tests
        virtual void SetUp(){} //sets up before each test (after constructor)
        virtual void TearDown(){} //clean up after each test, (before destructor)
};

TEST(PiezasTest, sanityCheck)
{
    ASSERT_TRUE(true);
}

TEST(PiezasTest, blankBoard)
{
    Piezas game;
    Piece board[3][4];
    int count = 0;

    for(int i = 0; i < 3; i++)
    {
        for(int j = 0; j < 4; j++)
        {
            if(board[j][i] == Blank)
            {
                count++;
            }
        }
    }
    ASSERT_EQ(count, 12);
}

TEST(PiezasTest, placeFirstX)
{
    Piezas game;
    Piece board[3][4];
    Piece confirm;

    confirm = game.dropPiece(2);

    ASSERT_EQ(confirm, board[2][2]);
}<commit_msg>Add files via upload<commit_after>/**
 * Unit Tests for Piezas
**/

#include <gtest/gtest.h>
#include "Piezas.h"

class PiezasTest : public ::testing::Test
{
    protected:
        PiezasTest(){} //constructor runs before each test
        virtual ~PiezasTest(){} //destructor cleans up after tests
        virtual void SetUp(){} //sets up before each test (after constructor)
        virtual void TearDown(){} //clean up after each test, (before destructor)
};

TEST(PiezasTest, sanityCheck)
{
    ASSERT_TRUE(true);
}

/*TEST(PiezasTest, blankBoard)
{
    Piezas game;
    Piece board[3][4];
    int count = 0;

    for(int i = 0; i < 3; i++)
    {
        for(int j = 0; j < 4; j++)
        {
            if(board[j][i] == Blank)
            {
                count++;
            }
        }
    }
    ASSERT_EQ(count, 12);
}*/

TEST(PiezasTest, placeFirstX)
{
    Piezas game;
    Piece board[3][4];
    Piece confirm;

    confirm = game.dropPiece(2);

    ASSERT_EQ(confirm, board[2][2]);
}<|endoftext|>


<commit_before>
#include <iostream>
#include <cstdlib>
#include <fstream>
#include <sstream>
#include <cmath>
#include <cassert>
#include <iomanip>
#include <cstdio>
#include <utility>
#include <algorithm>
#include <ios>
#include <limits>

#include <stdint.h>

#include <vector>
#include <string>
#include <cstring>
#include <list>
#include <map>
#include <set>
//#include <unordered_map>

using namespace std;

void print_vector_of_ints(string message, const vector<int>& vector_of_ints);
void print_vector_of_chars(string message, const vector<char>& vector_of_chars);
void print_vector_of_strings(string message, const vector<string>& vector_of_strings);
void print_vector_of_floats(string message, const vector<float>& vector_of_floats);
void print_vector_of_doubles(string message, const vector<double>& vector_of_doubles);

void print_list_of_ints(string message, list<int> list_of_ints);
void print_list_of_chars(string message, list<char> list_of_chars);
void print_list_of_strings(string message, list<string> list_of_strings);
void print_list_of_floats(string message, list<float> list_of_floats);
void print_list_of_doubles(string message, list<double> list_of_doubles);

void print_set_of_ints(string message, set<int> set_of_ints);
void print_set_of_chars(string message, set<char> set_of_chars);
void print_set_of_strings(string message, set<string> set_of_strings);
void print_set_of_floats(string message, set<float> set_of_floats);
void print_set_of_doubles(string message, set<double> set_of_doubles);

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

	vector<int> vector_of_ints;
	vector<char> vector_of_chars;
	vector<string> vector_of_strings;
	vector<float> vector_of_floats;
	vector<double> vector_of_doubles;

	list<int> list_of_ints;
	list<char> list_of_chars;
	list<string> list_of_strings;
	list<float> list_of_floats;
	list<double> list_of_doubles;

	set<int> set_of_ints;
	set<char> set_of_chars;
	set<string> set_of_strings;
	set<float> set_of_floats;
	set<double> set_of_doubles;

	vector_of_ints = {1, 2, 3};
	print_vector_of_ints("vertor of ints initialized by {}", vector_of_ints);

	vector_of_strings = {"cat", "meow", "kitty"};
	print_vector_of_strings("vertor of ints initialized by {}", vector_of_strings);

	vector_of_doubles = {1.0, 2.0, 3.0};
	print_vector_of_doubles("vertor of ints initialized by {}", vector_of_doubles);

	vector_of_floats = {12.0, 22.0, 32.0};
	print_vector_of_floats("vertor of ints initialized by {}", vector_of_floats);

	list_of_ints.push_back(2);
	list_of_ints.push_back(3);
	list_of_ints.push_back(4);
	list_of_ints.push_back(5);
	print_list_of_ints("testing function", list_of_ints);

	list_of_chars.push_back('a');
	list_of_chars.push_back('b');
	list_of_chars.push_back('c');
	list_of_chars.push_back('d');
	print_list_of_chars("testing function", list_of_chars);

	list_of_strings.push_back("hi");
	list_of_strings.push_back("there");
	list_of_strings.push_back("cout");
	list_of_strings.push_back("statement");
	print_list_of_strings("testing function", list_of_strings);

	list_of_floats.push_back(1.0);
	list_of_floats.push_back(2.0);
	list_of_floats.push_back(3.0);
	list_of_floats.push_back(4.0);
	print_list_of_floats("testing function", list_of_floats);

	list_of_doubles.push_back(11.0);
	list_of_doubles.push_back(21.0);
	list_of_doubles.push_back(31.0);
	list_of_doubles.push_back(41.0);
	print_list_of_doubles("testing function", list_of_doubles);

	//print_vector_of_ints("vector initialized given number and filler", vector_of_ints);

	return 0;
}

//=================================VECTORS===============================================

void print_vector_of_ints(string message, const vector<int>& vector_of_ints){
	cout << "-----------------------------------------------------------------" << endl;
	cout << message << endl << "[";
	for(unsigned int v = 0; v < vector_of_ints.size() -1; v++){
		cout << vector_of_ints[v] << ", ";
	}
	cout << vector_of_ints[vector_of_ints.size()-1] << "]" << endl;
	cout << "-----------------------------------------------------------------" << endl;
}

void print_vector_of_chars(string message, const vector<char>& vector_of_chars){
	cout << "-----------------------------------------------------------------" << endl;
	cout << message << endl << "[";
	for(unsigned int v = 0; v < vector_of_chars.size() -1; v++){
		cout << vector_of_chars[v] << ", ";
	}
	cout << vector_of_chars[vector_of_chars.size()-1] << "]" << endl;
	cout << "-----------------------------------------------------------------" << endl;
}

void print_vector_of_strings(string message, const vector<string>& vector_of_strings){
	cout << "-----------------------------------------------------------------" << endl;
	cout << message << endl << "[";
	for(unsigned int v = 0; v < vector_of_strings.size() -1; v++){
		cout << vector_of_strings[v] << ", ";
	}
	cout << vector_of_strings[vector_of_strings.size()-1] << "]" << endl;
	cout << "-----------------------------------------------------------------" << endl;
}

void print_vector_of_floats(string message, const vector<float>& vector_of_floats){
	cout << "-----------------------------------------------------------------" << endl;
	cout << message << endl << "[";
	for(unsigned int v = 0; v < vector_of_floats.size() -1; v++){
		cout << vector_of_floats[v] << ", ";
	}
	cout << vector_of_floats[vector_of_floats.size()-1] << "]" << endl;
	cout << "-----------------------------------------------------------------" << endl;
}

void print_vector_of_doubles(string message, const vector<double>& vector_of_doubles){
	cout << "-----------------------------------------------------------------" << endl;
	cout << message << endl << "[";
	for(unsigned int v = 0; v < vector_of_doubles.size() -1; v++){
		cout << vector_of_doubles[v] << ", ";
	}
	cout << vector_of_doubles[vector_of_doubles.size()-1] << "]" << endl;
	cout << "-----------------------------------------------------------------" << endl;
}

//=================================LISTS================================================

void print_list_of_ints(string message, list<int> list_of_ints){
	cout << "-----------------------------------------------------------------" << endl;
	cout << message << endl << "[";
	list<int>::iterator last_item_itr = list_of_ints.end();
	last_item_itr--;
	for(list<int>::iterator l = list_of_ints.begin(); l != last_item_itr; l++){
		cout << *l << ", ";
	}
	cout << *last_item_itr << "]" << endl;
	cout << "-----------------------------------------------------------------" << endl;
}

void print_list_of_chars(string message, list<char> list_of_chars){
	cout << "-----------------------------------------------------------------" << endl;
	cout << message << endl << "[";
	list<char>::iterator last_item_itr = list_of_chars.end();
	last_item_itr--;
	for(list<char>::iterator l = list_of_chars.begin(); l != last_item_itr; l++){
		cout << *l << ", ";
	}
	cout << *last_item_itr << "]" << endl;
	cout << "-----------------------------------------------------------------" << endl;
}

void print_list_of_strings(string message, list<string> list_of_strings){
	cout << "-----------------------------------------------------------------" << endl;
	cout << message << endl << "[";
	list<string>::iterator last_item_itr = list_of_strings.end();
	last_item_itr--;
	for(list<string>::iterator l = list_of_strings.begin(); l != last_item_itr; l++){
		cout << *l << ", ";
	}
	cout << *last_item_itr << "]" << endl;
	cout << "-----------------------------------------------------------------" << endl;
}

void print_list_of_floats(string message, list<float> list_of_floats){
	cout << "-----------------------------------------------------------------" << endl;
	cout << message << endl << "[";
	list<float>::iterator last_item_itr = list_of_floats.end();
	last_item_itr--;
	for(list<float>::iterator l = list_of_floats.begin(); l != last_item_itr; l++){
		cout << *l << ", ";
	}
	cout << *last_item_itr << "]" << endl;
	cout << "-----------------------------------------------------------------" << endl;
}

void print_list_of_doubles(string message, list<double> list_of_doubles){
	cout << "-----------------------------------------------------------------" << endl;
	cout << message << endl << "[";
	list<double>::iterator last_item_itr = list_of_doubles.end();
	last_item_itr--;
	for(list<double>::iterator l = list_of_doubles.begin(); l != last_item_itr; l++){
		cout << *l << ", ";
	}
	cout << *last_item_itr << "]" << endl;
	cout << "-----------------------------------------------------------------" << endl;
}

//==================================SETS================================================

void print_set_of_ints(string message, set<int> set_of_ints){
	cout << "-----------------------------------------------------------------" << endl;
	cout << message << endl << "[";
	set<int>::iterator last_item_itr = set_of_ints.end();
	last_item_itr--;
	for(set<int>::iterator l = set_of_ints.begin(); l != last_item_itr; l++){
		cout << *l << ", ";
	}
	cout << *last_item_itr << "]" << endl;
	cout << "-----------------------------------------------------------------" << endl;
}

void print_set_of_chars(string message, set<char> set_of_chars){
	cout << "-----------------------------------------------------------------" << endl;
	cout << message << endl << "[";
	set<char>::iterator last_item_itr = set_of_chars.end();
	last_item_itr--;
	for(set<char>::iterator l = set_of_chars.begin(); l != last_item_itr; l++){
		cout << *l << ", ";
	}
	cout << *last_item_itr << "]" << endl;
	cout << "-----------------------------------------------------------------" << endl;
}

void print_set_of_strings(string message, set<string> set_of_strings){
	cout << "-----------------------------------------------------------------" << endl;
	cout << message << endl << "[";
	set<string>::iterator last_item_itr = set_of_strings.end();
	last_item_itr--;
	for(set<string>::iterator l = set_of_strings.begin(); l != last_item_itr; l++){
		cout << *l << ", ";
	}
	cout << *last_item_itr << "]" << endl;
	cout << "-----------------------------------------------------------------" << endl;
}<commit_msg>changed lists, sets, and iterators to be const.  Lists and sets are also now references<commit_after>
#include <iostream>
#include <cstdlib>
#include <fstream>
#include <sstream>
#include <cmath>
#include <cassert>
#include <iomanip>
#include <cstdio>
#include <utility>
#include <algorithm>
#include <ios>
#include <limits>

#include <stdint.h>

#include <vector>
#include <string>
#include <cstring>
#include <list>
#include <map>
#include <set>
//#include <unordered_map>

using namespace std;

void print_vector_of_ints(const string& message, const vector<int>& vector_of_ints);
void print_vector_of_chars(const string& message, const vector<char>& vector_of_chars);
void print_vector_of_strings(const string& message, const vector<string>& vector_of_strings);
void print_vector_of_floats(const string& message, const vector<float>& vector_of_floats);
void print_vector_of_doubles(const string& message, const vector<double>& vector_of_doubles);

void print_list_of_ints(const string& message, const list<int>& list_of_ints);
void print_list_of_chars(const string& message, const list<char>& list_of_chars);
void print_list_of_strings(const string& message, const list<string>& list_of_strings);
void print_list_of_floats(const string& message, const list<float>& list_of_floats);
void print_list_of_doubles(const string& message, const list<double>& list_of_doubles);

void print_set_of_ints(const string& message, const set<int>& set_of_ints);
void print_set_of_chars(const string& message, const set<char>& set_of_chars);
void print_set_of_strings(const string& message, const set<string> &set_of_strings);
void print_set_of_floats(const string& message, const set<float>& set_of_floats);
void print_set_of_doubles(const string& message, const set<double>& set_of_doubles);

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

	vector<int> vector_of_ints;
	vector<char> vector_of_chars;
	vector<string> vector_of_strings;
	vector<float> vector_of_floats;
	vector<double> vector_of_doubles;

	list<int> list_of_ints;
	list<char> list_of_chars;
	list<string> list_of_strings;
	list<float> list_of_floats;
	list<double> list_of_doubles;

	set<int> set_of_ints;
	set<char> set_of_chars;
	set<string> set_of_strings;
	set<float> set_of_floats;
	set<double> set_of_doubles;

	vector_of_ints = {1, 2, 3};
	print_vector_of_ints("vertor of ints initialized by {}", vector_of_ints);

	vector_of_strings = {"cat", "meow", "kitty"};
	print_vector_of_strings("vertor of ints initialized by {}", vector_of_strings);

	vector_of_doubles = {1.0, 2.0, 3.0};
	print_vector_of_doubles("vertor of ints initialized by {}", vector_of_doubles);

	vector_of_floats = {12.0, 22.0, 32.0};
	print_vector_of_floats("vertor of ints initialized by {}", vector_of_floats);

	list_of_ints.push_back(2);
	list_of_ints.push_back(3);
	list_of_ints.push_back(4);
	list_of_ints.push_back(5);
	print_list_of_ints("testing function", list_of_ints);

	list_of_chars.push_back('a');
	list_of_chars.push_back('b');
	list_of_chars.push_back('c');
	list_of_chars.push_back('d');
	print_list_of_chars("testing function", list_of_chars);

	list_of_strings.push_back("hi");
	list_of_strings.push_back("there");
	list_of_strings.push_back("cout");
	list_of_strings.push_back("statement");
	print_list_of_strings("testing function", list_of_strings);

	list_of_floats.push_back(1.0);
	list_of_floats.push_back(2.0);
	list_of_floats.push_back(3.0);
	list_of_floats.push_back(4.0);
	print_list_of_floats("testing function", list_of_floats);

	list_of_doubles.push_back(11.0);
	list_of_doubles.push_back(21.0);
	list_of_doubles.push_back(31.0);
	list_of_doubles.push_back(41.0);
	print_list_of_doubles("testing function", list_of_doubles);

	//print_vector_of_ints("vector initialized given number and filler", vector_of_ints);

	return 0;
}

//=================================VECTORS===============================================

void print_vector_of_ints(const string& message, const vector<int>& vector_of_ints){
	cout << "-----------------------------------------------------------------" << endl;
	cout << message << endl << "[";
	for(unsigned int v = 0; v < vector_of_ints.size() -1; v++){
		cout << vector_of_ints[v] << ", ";
	}
	cout << vector_of_ints[vector_of_ints.size()-1] << "]" << endl;
	cout << "-----------------------------------------------------------------" << endl;
}

void print_vector_of_chars(const string& message, const vector<char>& vector_of_chars){
	cout << "-----------------------------------------------------------------" << endl;
	cout << message << endl << "[";
	for(unsigned int v = 0; v < vector_of_chars.size() -1; v++){
		cout << vector_of_chars[v] << ", ";
	}
	cout << vector_of_chars[vector_of_chars.size()-1] << "]" << endl;
	cout << "-----------------------------------------------------------------" << endl;
}

void print_vector_of_strings(const string& message, const vector<string>& vector_of_strings){
	cout << "-----------------------------------------------------------------" << endl;
	cout << message << endl << "[";
	for(unsigned int v = 0; v < vector_of_strings.size() -1; v++){
		cout << vector_of_strings[v] << ", ";
	}
	cout << vector_of_strings[vector_of_strings.size()-1] << "]" << endl;
	cout << "-----------------------------------------------------------------" << endl;
}

void print_vector_of_floats(const string& message, const vector<float>& vector_of_floats){
	cout << "-----------------------------------------------------------------" << endl;
	cout << message << endl << "[";
	for(unsigned int v = 0; v < vector_of_floats.size() -1; v++){
		cout << vector_of_floats[v] << ", ";
	}
	cout << vector_of_floats[vector_of_floats.size()-1] << "]" << endl;
	cout << "-----------------------------------------------------------------" << endl;
}

void print_vector_of_doubles(const string& message, const vector<double>& vector_of_doubles){
	cout << "-----------------------------------------------------------------" << endl;
	cout << message << endl << "[";
	for(unsigned int v = 0; v < vector_of_doubles.size() -1; v++){
		cout << vector_of_doubles[v] << ", ";
	}
	cout << vector_of_doubles[vector_of_doubles.size()-1] << "]" << endl;
	cout << "-----------------------------------------------------------------" << endl;
}

//=================================LISTS================================================

void print_list_of_ints(const string& message, const list<int>& list_of_ints){
	cout << "-----------------------------------------------------------------" << endl;
	cout << message << endl << "[";
	list<int>::const_iterator last_item_itr = list_of_ints.end();
	last_item_itr--;
	for(list<int>::const_iterator l = list_of_ints.begin(); l != last_item_itr; l++){
		cout << *l << ", ";
	}
	cout << *last_item_itr << "]" << endl;
	cout << "-----------------------------------------------------------------" << endl;
}

void print_list_of_chars(const string& message, const list<char>& list_of_chars){
	cout << "-----------------------------------------------------------------" << endl;
	cout << message << endl << "[";
	list<char>::const_iterator last_item_itr = list_of_chars.end();
	last_item_itr--;
	for(list<char>::const_iterator l = list_of_chars.begin(); l != last_item_itr; l++){
		cout << *l << ", ";
	}
	cout << *last_item_itr << "]" << endl;
	cout << "-----------------------------------------------------------------" << endl;
}

void print_list_of_strings(const string& message, const list<string>& list_of_strings){
	cout << "-----------------------------------------------------------------" << endl;
	cout << message << endl << "[";
	list<string>::const_iterator last_item_itr = list_of_strings.end();
	last_item_itr--;
	for(list<string>::const_iterator l = list_of_strings.begin(); l != last_item_itr; l++){
		cout << *l << ", ";
	}
	cout << *last_item_itr << "]" << endl;
	cout << "-----------------------------------------------------------------" << endl;
}

void print_list_of_floats(const string& message, const list<float>& list_of_floats){
	cout << "-----------------------------------------------------------------" << endl;
	cout << message << endl << "[";
	list<float>::const_iterator last_item_itr = list_of_floats.end();
	last_item_itr--;
	for(list<float>::const_iterator l = list_of_floats.begin(); l != last_item_itr; l++){
		cout << *l << ", ";
	}
	cout << *last_item_itr << "]" << endl;
	cout << "-----------------------------------------------------------------" << endl;
}

void print_list_of_doubles(const string& message, const list<double>& list_of_doubles){
	cout << "-----------------------------------------------------------------" << endl;
	cout << message << endl << "[";
	list<double>::const_iterator last_item_itr = list_of_doubles.end();
	last_item_itr--;
	for(list<double>::const_iterator l = list_of_doubles.begin(); l != last_item_itr; l++){
		cout << *l << ", ";
	}
	cout << *last_item_itr << "]" << endl;
	cout << "-----------------------------------------------------------------" << endl;
}

//==================================SETS================================================

void print_set_of_ints(const string& message, const set<int>& set_of_ints){
	cout << "-----------------------------------------------------------------" << endl;
	cout << message << endl << "[";
	set<int>::const_iterator last_item_itr = set_of_ints.end();
	last_item_itr--;
	for(set<int>::const_iterator l = set_of_ints.begin(); l != last_item_itr; l++){
		cout << *l << ", ";
	}
	cout << *last_item_itr << "]" << endl;
	cout << "-----------------------------------------------------------------" << endl;
}

void print_set_of_chars(const string& message, const set<char>& set_of_chars){
	cout << "-----------------------------------------------------------------" << endl;
	cout << message << endl << "[";
	set<char>::const_iterator last_item_itr = set_of_chars.end();
	last_item_itr--;
	for(set<char>::const_iterator l = set_of_chars.begin(); l != last_item_itr; l++){
		cout << *l << ", ";
	}
	cout << *last_item_itr << "]" << endl;
	cout << "-----------------------------------------------------------------" << endl;
}

void print_set_of_strings(const string& message, const set<string>& set_of_strings){
	cout << "-----------------------------------------------------------------" << endl;
	cout << message << endl << "[";
	set<string>::const_iterator last_item_itr = set_of_strings.end();
	last_item_itr--;
	for(set<string>::const_iterator l = set_of_strings.begin(); l != last_item_itr; l++){
		cout << *l << ", ";
	}
	cout << *last_item_itr << "]" << endl;
	cout << "-----------------------------------------------------------------" << endl;
}<|endoftext|>


<commit_before>// Copyright 2013 Robert McGibbon
#include "mpi.h"
#include "netcdf.h"
#include "math.h"
#include <sys/stat.h>
#include <cstdio>
#include <cstring> // strlen
#include <cstdlib>
#include <limits>  // for portable isinf/isnan
#include <vector>
#include <string>
#include <iostream>
#include "utilities.hpp"
#include "aligned_allocator.hpp"
#include "typedefs.hpp"
#include "NetCDFTrajectoryFile.hpp"
namespace Tungsten {
static const int MASTER = 0;

using std::string;
using std::vector;
using std::numeric_limits;

using namespace std;

// C++ doesn't seem to contain a portable isfinite() function unless you're
// using C++11. I got this idea from stack overflow. I'm not sure that it
// covers all of the corner cases, but it seems to work for common infs/nans.
template <typename T>
static inline bool isfinite(T x)  {
    return (x <= std::numeric_limits<T>::max() && x >= -std::numeric_limits<T>::max());
}

inline bool file_exists (const string& name) {
  struct stat buffer;
  return (stat (name.c_str(), &buffer) == 0);
}

NetCDFTrajectoryFile::NetCDFTrajectoryFile(const string& filename,
        const string& mode, int numAtoms = 0)
    : mode_(mode)
    , rank_(MPI::COMM_WORLD.Get_rank())
    , size_(MPI::COMM_WORLD.Get_size())
    , ncid_(NC_INVALID)
{

    if (mode_.compare("r") == 0) {
        if (int r = nc_open(filename.c_str(), NC_NOWRITE, &ncid_)) NC_ERR(r);
    } else if (mode_.compare("w") == 0) {
        if (file_exists(filename)) {
            if (int r = nc_open(filename.c_str(), NC_WRITE, &ncid_)) NC_ERR(r);
        } else
            if (int r = nc_create(filename.c_str(), NC_64BIT_OFFSET, &ncid_)) NC_ERR(r);
    } else
        exitWithMessage("NetCDFTrajectoryFile: Bad Mode");

    if (!isvalid())
        exitWithMessage("ERROR OPENING FILE Mode=%s\n", mode.c_str());

    int numDims;
    if (int r = nc_inq_ndims(ncid_, &numDims)) NC_ERR(r);
    if (numDims == 6) {
        loadHeaders();
        printf("Current size of frame=%ld\n", getNumFrames());
    } else if (mode_.compare("w") == 0 && numDims == 0)
        initializeHeaders(numAtoms);
    else
        exitWithMessage("Malformed AMBER NetCDF trajector file");
}

int NetCDFTrajectoryFile::loadHeaders() {
    int r;
    if (r = nc_inq_dimid(ncid_, "frame", &frameDim_)) NC_ERR(r);
    if (r = nc_inq_dimid(ncid_, "spatial", &spatialDim_)) NC_ERR(r);
    if (r = nc_inq_dimid(ncid_, "atom", &atomDim_)) NC_ERR(r);
    if (r = nc_inq_dimid(ncid_, "cell_spatial", &cellSpatialDim_)) NC_ERR(r);
    if (r = nc_inq_dimid(ncid_, "cell_angular", &cellAngularDim_)) NC_ERR(r);
    if (r = nc_inq_dimid(ncid_, "label", &labelDim_)) NC_ERR(r);

    if (r = nc_inq_varid(ncid_, "cell_spatial", &cellSpatialVar_)) NC_ERR(r);
    if (r = nc_inq_varid(ncid_, "cell_angular", &cellAngularVar_)) NC_ERR(r);
    if (r = nc_inq_varid(ncid_, "cell_lengths", &cellLengthsVar_)) NC_ERR(r);
    if (r = nc_inq_varid(ncid_, "cell_angles", &cellAnglesVar_)) NC_ERR(r);
    if (r = nc_inq_varid(ncid_, "time", &timeVar_)) NC_ERR(r);
    if (r = nc_inq_varid(ncid_, "coordinates", &coordVar_)) NC_ERR(r);
}

int NetCDFTrajectoryFile::initializeHeaders(int numAtoms) {
    int r;
    if (numAtoms <= 0) {
        exitWithMessage("Invalid number of atoms");
    }

    // declare the global attribues
    const char* title = "";
    const char* application = "OpenMM";
    const char* program = "Tungsten";
    const char* programVersion = "0.1";
    const char* Conventions = "AMBER";
    const char* ConventionsVersion = "1.0";

    // add the global attributes
    if (r = nc_put_att_text(ncid_, NC_GLOBAL, "title", strlen(title), title)) NC_ERR(r);
    if (r = nc_put_att_text(ncid_, NC_GLOBAL, "application", strlen(application), application)) NC_ERR(r);
    if (r = nc_put_att_text(ncid_, NC_GLOBAL, "program", strlen(program), program)) NC_ERR(r);
    if (r = nc_put_att_text(ncid_, NC_GLOBAL, "programVersion", strlen(programVersion), programVersion)) NC_ERR(r);
    if (r = nc_put_att_text(ncid_, NC_GLOBAL, "Conventions", strlen(Conventions), Conventions)) NC_ERR(r);
    if (r = nc_put_att_text(ncid_, NC_GLOBAL, "ConventionsVersion", strlen(ConventionsVersion), ConventionsVersion)) NC_ERR(r);

    if (r = nc_def_dim(ncid_, "frame", NC_UNLIMITED, &frameDim_)) NC_ERR(r);
    if (r = nc_def_dim(ncid_, "spatial", 3, &spatialDim_)) NC_ERR(r);
    if (r = nc_def_dim(ncid_, "atom", numAtoms, &atomDim_)) NC_ERR(r);
    if (r = nc_def_dim(ncid_, "cell_spatial", 3, &cellSpatialDim_)) NC_ERR(r);
    if (r = nc_def_dim(ncid_, "cell_angular", 3, &cellAngularDim_)) NC_ERR(r);
    if (r = nc_def_dim(ncid_, "label", 5, &labelDim_)) NC_ERR(r);

    int cellSpatialDimids[] = {spatialDim_};
    int cellAngularDimids[] = {spatialDim_, labelDim_};
    int cellLengthsDimids[] = {frameDim_, cellSpatialDim_};
    int cellAnglesDimids[]  = {frameDim_, cellAngularDim_};
    int timeDimids[]        = {frameDim_};
    int coordinatesDimids[] = {frameDim_, atomDim_, spatialDim_};
    if (r = nc_def_var(ncid_, "cell_spatial", NC_CHAR, 1, cellSpatialDimids, &cellSpatialVar_)) NC_ERR(r);
    if (r = nc_def_var(ncid_, "cell_angular", NC_CHAR, 2, cellAngularDimids, &cellAngularVar_)) NC_ERR(r);
    if (r = nc_def_var(ncid_, "cell_lengths", NC_DOUBLE, 2, cellLengthsDimids, &cellLengthsVar_)) NC_ERR(r);
    if (r = nc_def_var(ncid_, "cell_angles", NC_DOUBLE, 2, cellAnglesDimids, &cellAnglesVar_)) NC_ERR(r);
    if (r = nc_def_var(ncid_, "time", NC_FLOAT, 1, timeDimids, &timeVar_)) NC_ERR(r);
    if (r = nc_def_var(ncid_, "coordinates", NC_FLOAT, 3, coordinatesDimids, &coordVar_)) NC_ERR(r);

    // TODO: WRITE THESE ATTRIBUTES
    /*
    cellAnglesVar->add_att("units", "degree");
    cellLengthsVar->add_att("units", "angstrom");
    cellSpatialVar->put("XYZ", 3);
    cellAngularVar->put("alpha", 1, 5);
    cellAngularVar->set_cur(1, 0);
    cellAngularVar->put("beta", 1, 4);
    cellAngularVar->set_cur(2, 0);
    cellAngularVar->put("gamma", 1, 5);
    timeVar->add_att("units", "picosecond");
    coordVar->add_att("units", "angstrom");
    */

    if (r = nc_enddef(ncid_)) NC_ERR(r);
    return 1;
}

int NetCDFTrajectoryFile::write(OpenMM::State state) {
    if (mode_.compare("w") != 0)
        exitWithMessage("Writing is not allowed in this mode");
    int frame = getNumFrames();
    int numAtoms = getNumAtoms();

    OpenMM::Vec3 a;
    OpenMM::Vec3 b;
    OpenMM::Vec3 c;
    float time = state.getTime();
    state.getPeriodicBoxVectors(a, b, c);
    double cellLengths[] = {a[0]*10.0, b[1]*10.0, c[2]*10.0};
    double cellAngles[] = {90.0, 90.0, 90.0};
    vector<OpenMM::Vec3> mmPositions = state.getPositions();
    vector<float> positions(numAtoms*3);

    bool hasInfinite = false;
    for (int i = 0; i < numAtoms; i++)
        for (int j = 0; j < 3; j++) {
            if (!isfinite(mmPositions[i][0]) || !isfinite(mmPositions[i][1]) || !isfinite(mmPositions[i][2]))
                hasInfinite = true;
            positions[i*3 + j] = mmPositions[i][j] * 10.0;  // convert to angstroms
        }

    if (hasInfinite)
        for (int i = 0; i < positions.size(); i++)
            positions[i] = NAN;

    int r;  // errors
    const size_t index1[] = {frame};
    if (r = nc_put_var1_float(ncid_, timeVar_, index1, &time)) NC_ERR(r);

    const size_t index2[] = {frame, 0};
    const size_t count2[] = {1, 3};
    if (r = nc_put_vara_double(ncid_, cellLengthsVar_, index2, count2, cellLengths)) NC_ERR(r);
    if (r = nc_put_vara_double(ncid_, cellAnglesVar_, index2, count2, cellAngles)) NC_ERR(r);

    const size_t index3[] = {frame, 0, 0};
    const size_t count3[] = {1, getNumAtoms(), 3};
    if (r = nc_put_vara_float(ncid_, coordVar_, index3, count3, &positions[0])) NC_ERR(r);

    return 1;
}

PositionsAndPeriodicBox NetCDFTrajectoryFile::loadNonlocalStateMPI(int rank, int index) {
    const int magic1 = -12345;
    const int magic2 = -23456;
    const int tag1 = 123;
    const int tag2 = 234;

    // This could be done more efficiently by only exchanging the necessary pairs, but
    // its complex to get right without deadlocking because many nodes may request
    // data that all needs to come from one node. So lets just share *all* of the indices.
    // with Allgather.
    size_t numAtoms = getNumAtoms();
    vector<int> gatheredRank(size_);
    vector<int> gatheredIndex(size_);
    MPI::COMM_WORLD.Allgather(&rank, 1, MPI_INT, &gatheredRank[0], 1, MPI_INT);
    MPI::COMM_WORLD.Allgather(&index, 1, MPI_INT, &gatheredIndex[0], 1, MPI_INT);

    // Now, each node needs to look through the gatheredRank/gatheredSize and make
    // the appropriate send calls to give the data to the other nodes. It also
    // needs to obviously make its own receive call.
    vector<float> sendPositionsBuffer(numAtoms*3, magic1);
    vector<float> recvPositionsBuffer(numAtoms*3, magic2);
    vector<double> sendCellLengthsBuffer(3, magic1);
    vector<double> recvCellLengthsBuffer(3, magic2);
    // each node only gets one receive, but it may need to
    // make 0 or more sends
    MPI::Request recvRequest2, recvRequest1;
    vector<MPI::Request> sendRequests1, sendRequests2;

    for (int i = 0; i < size_; i++) {
        int j = gatheredRank[i];
        // j needs to send data to node i.
        // lets do the pair of send/recv.
        if (j == rank_) {
            // load the data into the send buffer
            size_t start3[] = {gatheredIndex[i], 0, 0};
            size_t count3[] = {1, numAtoms, 3};
            if (int r = nc_get_vara_float(ncid_, coordVar_, start3, count3, &sendPositionsBuffer[0])) NC_ERR(r);
            size_t start2[] = {gatheredIndex[i], 0};
            size_t count2[] = {1, 3};
            if (int r = nc_get_vara_double(ncid_, cellLengthsVar_, start2, count2, &sendCellLengthsBuffer[0])) NC_ERR(r);
            sendRequests1.push_back(MPI::COMM_WORLD.Isend(&sendPositionsBuffer[0],
                                    numAtoms*3, MPI_FLOAT, i, tag1));
            sendRequests2.push_back(MPI::COMM_WORLD.Isend(&sendCellLengthsBuffer[0],
                                    3, MPI_DOUBLE, i, tag2));
        }

        if (i == rank_) {
            // receive the data
            recvRequest1 = MPI::COMM_WORLD.Irecv(&recvPositionsBuffer[0],
                                                 numAtoms*3, MPI_FLOAT, j, tag1);
            recvRequest2 = MPI::COMM_WORLD.Irecv(&recvCellLengthsBuffer[0], 3,
                                                 MPI_DOUBLE, j, tag2);
        }
    }
    // make sure the nonblocking requests went through
    recvRequest1.Wait();
    for (int i = 0; i < sendRequests1.size(); i++)
        sendRequests1[i].Wait();
    recvRequest2.Wait();
    for (int i = 0; i < sendRequests2.size(); i++)
        sendRequests2[i].Wait();

    // reformat our recvBuffer into a vector of OpenMM::Vec3. Also convert
    // from loaded data in A to OpenMM's nm unit system.
    vector<OpenMM::Vec3> newPositions;
    for (int i = 0; i < numAtoms; i++) {
        OpenMM::Vec3 v(recvPositionsBuffer[i*3 + 0] / 10.0,
                       recvPositionsBuffer[i*3 + 1] / 10.0,
                       recvPositionsBuffer[i*3 + 2] / 10.0);
        newPositions.push_back(v);
    }

    PositionsAndPeriodicBox retval;
    retval.positions = newPositions;
    retval.boxA = OpenMM::Vec3(recvCellLengthsBuffer[0] / 10.0, 0, 0);
    retval.boxB = OpenMM::Vec3(0, recvCellLengthsBuffer[1] / 10.0, 0);
    retval.boxC = OpenMM::Vec3(0, 0, recvCellLengthsBuffer[2] / 10.0);

    return retval;
}

}  // namespace
<commit_msg>print the appropriate title and the axis metadata<commit_after>// Copyright 2013 Robert McGibbon
#include "mpi.h"
#include "netcdf.h"
#include "sys/utsname.h"  // for uname info in title
#include <time.h>  // for creation info in title
#include "math.h"
#include <sys/stat.h>
#include <cstdio>
#include <sstream>
#include <cstring> // strlen
#include <cstdlib>
#include <limits>  // for portable isinf/isnan
#include <vector>
#include <string>
#include <iostream>
#include "utilities.hpp"
#include "aligned_allocator.hpp"
#include "typedefs.hpp"
#include "NetCDFTrajectoryFile.hpp"
namespace Tungsten {
static const int MASTER = 0;

using std::string;
using std::vector;
using std::numeric_limits;
using std::stringstream;

using namespace std;

// C++ doesn't seem to contain a portable isfinite() function unless you're
// using C++11. I got this idea from stack overflow. I'm not sure that it
// covers all of the corner cases, but it seems to work for common infs/nans.
template <typename T>
static inline bool isfinite(T x)  {
    return (x <= std::numeric_limits<T>::max() && x >= -std::numeric_limits<T>::max());
}

inline bool file_exists (const string& name) {
    struct stat buffer;
    return (stat (name.c_str(), &buffer) == 0);
}

NetCDFTrajectoryFile::NetCDFTrajectoryFile(const string& filename,
        const string& mode, int numAtoms = 0)
    : mode_(mode)
    , rank_(MPI::COMM_WORLD.Get_rank())
    , size_(MPI::COMM_WORLD.Get_size())
    , ncid_(NC_INVALID) {

    if (mode_.compare("r") == 0) {
        if (int r = nc_open(filename.c_str(), NC_NOWRITE, &ncid_)) NC_ERR(r);
    } else if (mode_.compare("w") == 0) {
        if (file_exists(filename)) {
            if (int r = nc_open(filename.c_str(), NC_WRITE, &ncid_)) NC_ERR(r);
        } else
            if (int r = nc_create(filename.c_str(), NC_64BIT_OFFSET, &ncid_)) NC_ERR(r);
    } else
        exitWithMessage("NetCDFTrajectoryFile: Bad Mode");

    if (!isvalid())
        exitWithMessage("ERROR OPENING FILE Mode=%s\n", mode.c_str());

    int numDims;
    if (int r = nc_inq_ndims(ncid_, &numDims)) NC_ERR(r);
    if (numDims == 6) {
        loadHeaders();
        printf("Current size of frame=%ld\n", getNumFrames());
    } else if (mode_.compare("w") == 0 && numDims == 0)
        initializeHeaders(numAtoms);
    else
        exitWithMessage("Malformed AMBER NetCDF trajector file");
}

int NetCDFTrajectoryFile::loadHeaders() {
    int r;
    if (r = nc_inq_dimid(ncid_, "frame", &frameDim_)) NC_ERR(r);
    if (r = nc_inq_dimid(ncid_, "spatial", &spatialDim_)) NC_ERR(r);
    if (r = nc_inq_dimid(ncid_, "atom", &atomDim_)) NC_ERR(r);
    if (r = nc_inq_dimid(ncid_, "cell_spatial", &cellSpatialDim_)) NC_ERR(r);
    if (r = nc_inq_dimid(ncid_, "cell_angular", &cellAngularDim_)) NC_ERR(r);
    if (r = nc_inq_dimid(ncid_, "label", &labelDim_)) NC_ERR(r);

    if (r = nc_inq_varid(ncid_, "cell_spatial", &cellSpatialVar_)) NC_ERR(r);
    if (r = nc_inq_varid(ncid_, "cell_angular", &cellAngularVar_)) NC_ERR(r);
    if (r = nc_inq_varid(ncid_, "cell_lengths", &cellLengthsVar_)) NC_ERR(r);
    if (r = nc_inq_varid(ncid_, "cell_angles", &cellAnglesVar_)) NC_ERR(r);
    if (r = nc_inq_varid(ncid_, "time", &timeVar_)) NC_ERR(r);
    if (r = nc_inq_varid(ncid_, "coordinates", &coordVar_)) NC_ERR(r);
}

int NetCDFTrajectoryFile::initializeHeaders(int numAtoms) {
    int r;
    if (numAtoms <= 0) {
        exitWithMessage("Invalid number of atoms");
    }

    // produce the title to use
    char title[512];  // go a little overkill here, just to avoid a buffer overflow
    time_t curtime = time (NULL);
    struct utsname sysinfo;
    uname(&sysinfo);
    strftime(title, 512, "Tungsten Adaptive Sampling\nCreated: %Y-%m-%d %H:%M:%S\n", localtime(&curtime));
    sprintf(&title[56], "System: %s %s %s %s\nOpenMMVersion: %s", sysinfo.nodename, sysinfo.sysname, sysinfo.release, sysinfo.machine, OpenMM::Platform::getOpenMMVersion().c_str());

    // declare the global attribues
    const char* application = "OpenMM";
    const char* program = "Tungsten";
    const char* programVersion = "0.1";
    const char* Conventions = "AMBER";
    const char* ConventionsVersion = "1.0";

    // add the global attributes
    if (r = nc_put_att_text(ncid_, NC_GLOBAL, "title", strlen(title)+1, title)) NC_ERR(r);
    if (r = nc_put_att_text(ncid_, NC_GLOBAL, "application", strlen(application)+1, application)) NC_ERR(r);
    if (r = nc_put_att_text(ncid_, NC_GLOBAL, "program", strlen(program)+1, program)) NC_ERR(r);
    if (r = nc_put_att_text(ncid_, NC_GLOBAL, "programVersion", strlen(programVersion)+1, programVersion)) NC_ERR(r);
    if (r = nc_put_att_text(ncid_, NC_GLOBAL, "Conventions", strlen(Conventions)+1, Conventions)) NC_ERR(r);
    if (r = nc_put_att_text(ncid_, NC_GLOBAL, "ConventionsVersion", strlen(ConventionsVersion)+1, ConventionsVersion)) NC_ERR(r);

    if (r = nc_def_dim(ncid_, "frame", NC_UNLIMITED, &frameDim_)) NC_ERR(r);
    if (r = nc_def_dim(ncid_, "spatial", 3, &spatialDim_)) NC_ERR(r);
    if (r = nc_def_dim(ncid_, "atom", numAtoms, &atomDim_)) NC_ERR(r);
    if (r = nc_def_dim(ncid_, "cell_spatial", 3, &cellSpatialDim_)) NC_ERR(r);
    if (r = nc_def_dim(ncid_, "cell_angular", 3, &cellAngularDim_)) NC_ERR(r);
    if (r = nc_def_dim(ncid_, "label", 5, &labelDim_)) NC_ERR(r);

    int cellSpatialDimids[] = {spatialDim_};
    int cellAngularDimids[] = {spatialDim_, labelDim_};
    int cellLengthsDimids[] = {frameDim_, cellSpatialDim_};
    int cellAnglesDimids[]  = {frameDim_, cellAngularDim_};
    int timeDimids[]        = {frameDim_};
    int coordinatesDimids[] = {frameDim_, atomDim_, spatialDim_};
    if (r = nc_def_var(ncid_, "cell_spatial", NC_CHAR, 1, cellSpatialDimids, &cellSpatialVar_)) NC_ERR(r);
    if (r = nc_def_var(ncid_, "cell_angular", NC_CHAR, 2, cellAngularDimids, &cellAngularVar_)) NC_ERR(r);
    if (r = nc_def_var(ncid_, "cell_lengths", NC_DOUBLE, 2, cellLengthsDimids, &cellLengthsVar_)) NC_ERR(r);
    if (r = nc_def_var(ncid_, "cell_angles", NC_DOUBLE, 2, cellAnglesDimids, &cellAnglesVar_)) NC_ERR(r);
    if (r = nc_def_var(ncid_, "time", NC_FLOAT, 1, timeDimids, &timeVar_)) NC_ERR(r);
    if (r = nc_def_var(ncid_, "coordinates", NC_FLOAT, 3, coordinatesDimids, &coordVar_)) NC_ERR(r);

    // TODO: WRITE THESE ATTRIBUTES
    const char* degree = "degree";
    const char* angstrom = "angstrom";
    const char* picoseconds = "picoseconds";
    const char* xyz = "XYZ";
    const char* alphabetagamma = "alphabeta\0gamma";
    if (r = nc_put_att_text(ncid_, cellAnglesVar_, "units", strlen(degree), degree)) NC_ERR(r);
    if (r = nc_put_att_text(ncid_, cellLengthsVar_, "units", strlen(angstrom), angstrom)) NC_ERR(r);
    if (r = nc_put_att_text(ncid_, timeVar_, "units", strlen(picoseconds), picoseconds)) NC_ERR(r);
    if (r = nc_put_att_text(ncid_, coordVar_, "units", strlen(angstrom), angstrom)) NC_ERR(r);

    if (r = nc_enddef(ncid_)) NC_ERR(r);

    if (r = nc_put_var_text(ncid_, cellSpatialVar_, xyz)) NC_ERR(r);
    if (r = nc_put_var_text(ncid_, cellAngularVar_, alphabetagamma)) NC_ERR(r);
    return 1;
}

int NetCDFTrajectoryFile::write(OpenMM::State state) {
    if (mode_.compare("w") != 0)
        exitWithMessage("Writing is not allowed in this mode");
    int frame = getNumFrames();
    int numAtoms = getNumAtoms();

    OpenMM::Vec3 a;
    OpenMM::Vec3 b;
    OpenMM::Vec3 c;
    float time = state.getTime();
    state.getPeriodicBoxVectors(a, b, c);
    double cellLengths[] = {a[0]*10.0, b[1]*10.0, c[2]*10.0};
    double cellAngles[] = {90.0, 90.0, 90.0};
    vector<OpenMM::Vec3> mmPositions = state.getPositions();
    vector<float> positions(numAtoms*3);

    bool hasInfinite = false;
    for (int i = 0; i < numAtoms; i++)
        for (int j = 0; j < 3; j++) {
            if (!isfinite(mmPositions[i][0]) || !isfinite(mmPositions[i][1]) || !isfinite(mmPositions[i][2]))
                hasInfinite = true;
            positions[i*3 + j] = mmPositions[i][j] * 10.0;  // convert to angstroms
        }

    if (hasInfinite)
        for (int i = 0; i < positions.size(); i++)
            positions[i] = NAN;

    int r;  // errors
    const size_t index1[] = {frame};
    if (r = nc_put_var1_float(ncid_, timeVar_, index1, &time)) NC_ERR(r);

    const size_t index2[] = {frame, 0};
    const size_t count2[] = {1, 3};
    if (r = nc_put_vara_double(ncid_, cellLengthsVar_, index2, count2, cellLengths)) NC_ERR(r);
    if (r = nc_put_vara_double(ncid_, cellAnglesVar_, index2, count2, cellAngles)) NC_ERR(r);

    const size_t index3[] = {frame, 0, 0};
    const size_t count3[] = {1, getNumAtoms(), 3};
    if (r = nc_put_vara_float(ncid_, coordVar_, index3, count3, &positions[0])) NC_ERR(r);

    return 1;
}

PositionsAndPeriodicBox NetCDFTrajectoryFile::loadNonlocalStateMPI(int rank, int index) {
    const int magic1 = -12345;
    const int magic2 = -23456;
    const int tag1 = 123;
    const int tag2 = 234;

    // This could be done more efficiently by only exchanging the necessary pairs, but
    // its complex to get right without deadlocking because many nodes may request
    // data that all needs to come from one node. So lets just share *all* of the indices.
    // with Allgather.
    size_t numAtoms = getNumAtoms();
    vector<int> gatheredRank(size_);
    vector<int> gatheredIndex(size_);
    MPI::COMM_WORLD.Allgather(&rank, 1, MPI_INT, &gatheredRank[0], 1, MPI_INT);
    MPI::COMM_WORLD.Allgather(&index, 1, MPI_INT, &gatheredIndex[0], 1, MPI_INT);

    // Now, each node needs to look through the gatheredRank/gatheredSize and make
    // the appropriate send calls to give the data to the other nodes. It also
    // needs to obviously make its own receive call.
    vector<float> sendPositionsBuffer(numAtoms*3, magic1);
    vector<float> recvPositionsBuffer(numAtoms*3, magic2);
    vector<double> sendCellLengthsBuffer(3, magic1);
    vector<double> recvCellLengthsBuffer(3, magic2);
    // each node only gets one receive, but it may need to
    // make 0 or more sends
    MPI::Request recvRequest2, recvRequest1;
    vector<MPI::Request> sendRequests1, sendRequests2;

    for (int i = 0; i < size_; i++) {
        int j = gatheredRank[i];
        // j needs to send data to node i.
        // lets do the pair of send/recv.
        if (j == rank_) {
            // load the data into the send buffer
            size_t start3[] = {gatheredIndex[i], 0, 0};
            size_t count3[] = {1, numAtoms, 3};
            if (int r = nc_get_vara_float(ncid_, coordVar_, start3, count3, &sendPositionsBuffer[0])) NC_ERR(r);
            size_t start2[] = {gatheredIndex[i], 0};
            size_t count2[] = {1, 3};
            if (int r = nc_get_vara_double(ncid_, cellLengthsVar_, start2, count2, &sendCellLengthsBuffer[0])) NC_ERR(r);
            sendRequests1.push_back(MPI::COMM_WORLD.Isend(&sendPositionsBuffer[0],
                                    numAtoms*3, MPI_FLOAT, i, tag1));
            sendRequests2.push_back(MPI::COMM_WORLD.Isend(&sendCellLengthsBuffer[0],
                                    3, MPI_DOUBLE, i, tag2));
        }

        if (i == rank_) {
            // receive the data
            recvRequest1 = MPI::COMM_WORLD.Irecv(&recvPositionsBuffer[0],
                                                 numAtoms*3, MPI_FLOAT, j, tag1);
            recvRequest2 = MPI::COMM_WORLD.Irecv(&recvCellLengthsBuffer[0], 3,
                                                 MPI_DOUBLE, j, tag2);
        }
    }
    // make sure the nonblocking requests went through
    recvRequest1.Wait();
    for (int i = 0; i < sendRequests1.size(); i++)
        sendRequests1[i].Wait();
    recvRequest2.Wait();
    for (int i = 0; i < sendRequests2.size(); i++)
        sendRequests2[i].Wait();

    // reformat our recvBuffer into a vector of OpenMM::Vec3. Also convert
    // from loaded data in A to OpenMM's nm unit system.
    vector<OpenMM::Vec3> newPositions;
    for (int i = 0; i < numAtoms; i++) {
        OpenMM::Vec3 v(recvPositionsBuffer[i*3 + 0] / 10.0,
                       recvPositionsBuffer[i*3 + 1] / 10.0,
                       recvPositionsBuffer[i*3 + 2] / 10.0);
        newPositions.push_back(v);
    }

    PositionsAndPeriodicBox retval;
    retval.positions = newPositions;
    retval.boxA = OpenMM::Vec3(recvCellLengthsBuffer[0] / 10.0, 0, 0);
    retval.boxB = OpenMM::Vec3(0, recvCellLengthsBuffer[1] / 10.0, 0);
    retval.boxC = OpenMM::Vec3(0, 0, recvCellLengthsBuffer[2] / 10.0);

    return retval;
}

}  // namespace
<|endoftext|>