<commit_before>/******************************************************************************
 *                    _   _____   __________                                  *
 *                   | | / / _ | / __/_  __/     Visibility                   *
 *                   | |/ / __ |_\ \  / /          Across                     *
 *                   |___/_/ |_/___/ /_/       Space and Time                 *
 *                                                                            *
 * This file is part of VAST. It is subject to the license terms in the       *
 * LICENSE file found in the top-level directory of this distribution and at  *
 * http://vast.io/license. No part of VAST, including this file, may be       *
 * copied, modified, propagated, or distributed except according to the terms *
 * contained in the LICENSE file.                                             *
 ******************************************************************************/

#include "fixtures/events.hpp"

#include "vast/const_table_slice_handle.hpp"
#include "vast/default_table_slice.hpp"
#include "vast/format/bgpdump.hpp"
#include "vast/format/bro.hpp"
#include "vast/format/test.hpp"
#include "vast/table_slice_builder.hpp"
#include "vast/table_slice_handle.hpp"
#include "vast/type.hpp"

namespace fixtures {

namespace {

timestamp epoch;

std::vector<event> make_ascending_integers(size_t count) {
  std::vector<event> result;
  type layout = type{record_type{{"value", integer_type{}}}}.name("test::int");
  for (size_t i = 0; i < count; ++i) {
    result.emplace_back(event::make(vector{static_cast<integer>(i)}, layout));
    result.back().timestamp(epoch + std::chrono::seconds(i));
  }
  return result;
}

std::vector<event> make_alternating_integers(size_t count) {
  std::vector<event> result;
  type layout = type{record_type{{"value", integer_type{}}}}.name("test::int");
  for (size_t i = 0; i < count; ++i) {
    result.emplace_back(event::make(vector{static_cast<integer>(i % 2)},
                                    layout));
    result.back().timestamp(epoch + std::chrono::seconds(i));
  }
  return result;
}

} // namespace <anonymous>

size_t events::slice_size = 100;

std::vector<event> events::bro_conn_log;
std::vector<event> events::bro_dns_log;
std::vector<event> events::bro_http_log;
std::vector<event> events::bgpdump_txt;
std::vector<event> events::random;

std::vector<table_slice_handle> events::bro_conn_log_slices;
// std::vector<table_slice_handle> events::bro_dns_log_slices;
// std::vector<table_slice_handle> events::bro_http_log_slices;
// std::vector<table_slice_handle> events::bgpdump_txt_slices;
// std::vector<table_slice_handle> events::random_slices;

std::vector<const_table_slice_handle> events::const_bro_conn_log_slices;
// std::vector<const_table_slice_handle> events::const_bro_http_log_slices;
// std::vector<const_table_slice_handle> events::const_bro_dns_log_slices;
// std::vector<const_table_slice_handle> events::const_bgpdump_txt_slices;
// std::vector<const_table_slice_handle> events::const_random_slices;

std::vector<event> events::ascending_integers;
std::vector<table_slice_handle> events::ascending_integers_slices;
std::vector<const_table_slice_handle> events::const_ascending_integers_slices;

std::vector<event> events::alternating_integers;
std::vector<table_slice_handle> events::alternating_integers_slices;
std::vector<const_table_slice_handle> events::const_alternating_integers_slices;

record_type events::bro_conn_log_layout() {
  return const_bro_conn_log_slices[0]->layout();
}

std::vector<table_slice_handle>
events::copy(std::vector<table_slice_handle> xs) {
  std::vector<table_slice_handle> result;
  result.reserve(xs.size());
  for (auto& x : xs)
    result.emplace_back(x->clone());
  return result;
}

events::events() {
  static bool initialized = false;
  if (initialized)
    return;
  initialized = true;
  MESSAGE("inhaling unit test suite events");
  bro_conn_log = inhale<format::bro::reader>(bro::conn);
  bro_dns_log = inhale<format::bro::reader>(bro::dns);
  bro_http_log = inhale<format::bro::reader>(bro::http);
  bgpdump_txt = inhale<format::bgpdump::reader>(bgpdump::updates20140821);
  random = extract(vast::format::test::reader{42, 1000});
  ascending_integers = make_ascending_integers(10000);
  alternating_integers = make_alternating_integers(10000);
  // Assign monotonic IDs to events starting at 0.
  auto i = id{0};
  auto assign = [&](auto& xs) {
    for (auto& x : xs)
      x.id(i++);
  };
  assign(bro_conn_log);
  assign(bro_dns_log);
  i += 1000; // Cause an artificial gap in the ID sequence.
  assign(bro_http_log);
  assign(bgpdump_txt);
  assign(ascending_integers);
  assign(alternating_integers);
  MESSAGE("building slices of " << slice_size << " events each");
  auto slice_up = [&](const std::vector<event>& src) {
    VAST_ASSERT(src.size() > 0);
    VAST_ASSERT(caf::holds_alternative<record_type>(src[0].type()));
    auto layout = caf::get<record_type>(src[0].type());
    record_field tstamp_field{"timestamp", timestamp_type{}};
    layout.fields.insert(layout.fields.begin(), std::move(tstamp_field));
    auto builder = default_table_slice::make_builder(std::move(layout));
    auto full_slices = src.size() / slice_size;
    std::vector<table_slice_handle> slices;
    auto i = src.begin();
    auto make_slice = [&](size_t size) {
      if (size == 0)
        return;
      auto first_id_in_slice = i->id();
      for (size_t j = 0; j < size; ++j) {
        auto& e = *i++;
        auto add_res = builder->add(e.timestamp());
        if (!add_res)
          FAIL("builder->add() failed");
        auto rec_add_res = builder->recursive_add(e.data());
        if (!rec_add_res)
          FAIL("builder->recursive_add() failed");
      }
      slices.emplace_back(builder->finish());
      slices.back()->offset(first_id_in_slice);
    };
    // Insert full slices.
    for (size_t i = 0; i < full_slices; ++i)
      make_slice(slice_size);
    // Insert remaining events.
    make_slice(src.size() % slice_size);
    return slices;
  };
  bro_conn_log_slices = slice_up(bro_conn_log);
  //bro_dns_log_slices = slice_up(bro_dns_log);
  //bro_http_log_slices = slice_up(bro_http_log);
  //bgpdump_txt_slices = slice_up(bgpdump_txt);
  //random_slices = slice_up(random);
  ascending_integers_slices = slice_up(ascending_integers);
  alternating_integers_slices = slice_up(alternating_integers);
  auto to_const_vector = [](const auto& xs) {
    std::vector<const_table_slice_handle> result;
    result.reserve(xs.size());
    result.insert(result.end(), xs.begin(), xs.end());
    return result;
  };
  const_bro_conn_log_slices = to_const_vector(bro_conn_log_slices);
  // const_bro_dns_log_slices = to_const_vector(bro_dns_log_slices);
  // const_bro_http_log_slices = to_const_vector(bro_http_log_slices);
  // const_bgpdump_txt_slices = to_const_vector(bgpdump_txt_slices);
  // const_random_slices = to_const_vector(random_slices);
  const_ascending_integers_slices = to_const_vector(ascending_integers_slices);
  const_alternating_integers_slices
    = to_const_vector(alternating_integers_slices);
  auto to_events = [](const auto& slices) {
    std::vector<event> result;
    for (auto& slice : slices) {
      auto xs = slice->rows_to_events();
      std::move(xs.begin(), xs.end(), std::back_inserter(result));
    }
    return result;
  };
#define SANITY_CHECK(event_vec, slice_vec)                                     \
  {                                                                            \
    auto flat_log = to_events(slice_vec);                                      \
    REQUIRE_EQUAL(event_vec.size(), flat_log.size());                          \
    for (size_t i = 0; i < event_vec.size(); ++i) {                            \
      if (flatten(event_vec[i]) != flat_log[i]) {                              \
        FAIL(#event_vec << " != " << #slice_vec);                              \
      }                                                                        \
    }                                                                          \
  }
  SANITY_CHECK(bro_conn_log, const_bro_conn_log_slices);
  //SANITY_CHECK(bro_dns_log, const_bro_dns_log_slices);
  //SANITY_CHECK(bro_http_log, const_bro_http_log_slices);
  //SANITY_CHECK(bgpdump_txt, const_bgpdump_txt_slices);
  //SANITY_CHECK(random, const_random_slices);
}

} // namespace fixtures
<commit_msg>Ensure correct number of fixture events<commit_after>/******************************************************************************
 *                    _   _____   __________                                  *
 *                   | | / / _ | / __/_  __/     Visibility                   *
 *                   | |/ / __ |_\ \  / /          Across                     *
 *                   |___/_/ |_/___/ /_/       Space and Time                 *
 *                                                                            *
 * This file is part of VAST. It is subject to the license terms in the       *
 * LICENSE file found in the top-level directory of this distribution and at  *
 * http://vast.io/license. No part of VAST, including this file, may be       *
 * copied, modified, propagated, or distributed except according to the terms *
 * contained in the LICENSE file.                                             *
 ******************************************************************************/

#include "fixtures/events.hpp"

#include "vast/const_table_slice_handle.hpp"
#include "vast/default_table_slice.hpp"
#include "vast/format/bgpdump.hpp"
#include "vast/format/bro.hpp"
#include "vast/format/test.hpp"
#include "vast/table_slice_builder.hpp"
#include "vast/table_slice_handle.hpp"
#include "vast/type.hpp"

namespace fixtures {

namespace {

timestamp epoch;

std::vector<event> make_ascending_integers(size_t count) {
  std::vector<event> result;
  type layout = type{record_type{{"value", integer_type{}}}}.name("test::int");
  for (size_t i = 0; i < count; ++i) {
    result.emplace_back(event::make(vector{static_cast<integer>(i)}, layout));
    result.back().timestamp(epoch + std::chrono::seconds(i));
  }
  return result;
}

std::vector<event> make_alternating_integers(size_t count) {
  std::vector<event> result;
  type layout = type{record_type{{"value", integer_type{}}}}.name("test::int");
  for (size_t i = 0; i < count; ++i) {
    result.emplace_back(event::make(vector{static_cast<integer>(i % 2)},
                                    layout));
    result.back().timestamp(epoch + std::chrono::seconds(i));
  }
  return result;
}

} // namespace <anonymous>

size_t events::slice_size = 100;

std::vector<event> events::bro_conn_log;
std::vector<event> events::bro_dns_log;
std::vector<event> events::bro_http_log;
std::vector<event> events::bgpdump_txt;
std::vector<event> events::random;

std::vector<table_slice_handle> events::bro_conn_log_slices;
// std::vector<table_slice_handle> events::bro_dns_log_slices;
// std::vector<table_slice_handle> events::bro_http_log_slices;
// std::vector<table_slice_handle> events::bgpdump_txt_slices;
// std::vector<table_slice_handle> events::random_slices;

std::vector<const_table_slice_handle> events::const_bro_conn_log_slices;
// std::vector<const_table_slice_handle> events::const_bro_http_log_slices;
// std::vector<const_table_slice_handle> events::const_bro_dns_log_slices;
// std::vector<const_table_slice_handle> events::const_bgpdump_txt_slices;
// std::vector<const_table_slice_handle> events::const_random_slices;

std::vector<event> events::ascending_integers;
std::vector<table_slice_handle> events::ascending_integers_slices;
std::vector<const_table_slice_handle> events::const_ascending_integers_slices;

std::vector<event> events::alternating_integers;
std::vector<table_slice_handle> events::alternating_integers_slices;
std::vector<const_table_slice_handle> events::const_alternating_integers_slices;

record_type events::bro_conn_log_layout() {
  return const_bro_conn_log_slices[0]->layout();
}

std::vector<table_slice_handle>
events::copy(std::vector<table_slice_handle> xs) {
  std::vector<table_slice_handle> result;
  result.reserve(xs.size());
  for (auto& x : xs)
    result.emplace_back(x->clone());
  return result;
}

events::events() {
  static bool initialized = false;
  if (initialized)
    return;
  initialized = true;
  MESSAGE("inhaling unit test suite events");
  bro_conn_log = inhale<format::bro::reader>(bro::conn);
  REQUIRE_EQUAL(bro_conn_log.size(), 8462u);
  bro_dns_log = inhale<format::bro::reader>(bro::dns);
  REQUIRE_EQUAL(bro_dns_log.size(), 5124u);
  bro_http_log = inhale<format::bro::reader>(bro::http);
  REQUIRE_EQUAL(bro_http_log.size(), 4896u);
  bgpdump_txt = inhale<format::bgpdump::reader>(bgpdump::updates20140821);
  REQUIRE_EQUAL(bgpdump_txt.size(), 11782u);
  random = extract(vast::format::test::reader{42, 1000});
  REQUIRE_EQUAL(random.size(), 1000u);
  ascending_integers = make_ascending_integers(10000);
  alternating_integers = make_alternating_integers(10000);
  // Assign monotonic IDs to events starting at 0.
  auto i = id{0};
  auto assign = [&](auto& xs) {
    for (auto& x : xs)
      x.id(i++);
  };
  assign(bro_conn_log);
  assign(bro_dns_log);
  i += 1000; // Cause an artificial gap in the ID sequence.
  assign(bro_http_log);
  assign(bgpdump_txt);
  assign(ascending_integers);
  assign(alternating_integers);
  MESSAGE("building slices of " << slice_size << " events each");
  auto slice_up = [&](const std::vector<event>& src) {
    VAST_ASSERT(src.size() > 0);
    VAST_ASSERT(caf::holds_alternative<record_type>(src[0].type()));
    auto layout = caf::get<record_type>(src[0].type());
    record_field tstamp_field{"timestamp", timestamp_type{}};
    layout.fields.insert(layout.fields.begin(), std::move(tstamp_field));
    auto builder = default_table_slice::make_builder(std::move(layout));
    auto full_slices = src.size() / slice_size;
    std::vector<table_slice_handle> slices;
    auto i = src.begin();
    auto make_slice = [&](size_t size) {
      if (size == 0)
        return;
      auto first_id_in_slice = i->id();
      for (size_t j = 0; j < size; ++j) {
        auto& e = *i++;
        auto add_res = builder->add(e.timestamp());
        if (!add_res)
          FAIL("builder->add() failed");
        auto rec_add_res = builder->recursive_add(e.data());
        if (!rec_add_res)
          FAIL("builder->recursive_add() failed");
      }
      slices.emplace_back(builder->finish());
      slices.back()->offset(first_id_in_slice);
    };
    // Insert full slices.
    for (size_t i = 0; i < full_slices; ++i)
      make_slice(slice_size);
    // Insert remaining events.
    make_slice(src.size() % slice_size);
    return slices;
  };
  bro_conn_log_slices = slice_up(bro_conn_log);
  //bro_dns_log_slices = slice_up(bro_dns_log);
  //bro_http_log_slices = slice_up(bro_http_log);
  //bgpdump_txt_slices = slice_up(bgpdump_txt);
  //random_slices = slice_up(random);
  ascending_integers_slices = slice_up(ascending_integers);
  alternating_integers_slices = slice_up(alternating_integers);
  auto to_const_vector = [](const auto& xs) {
    std::vector<const_table_slice_handle> result;
    result.reserve(xs.size());
    result.insert(result.end(), xs.begin(), xs.end());
    return result;
  };
  const_bro_conn_log_slices = to_const_vector(bro_conn_log_slices);
  // const_bro_dns_log_slices = to_const_vector(bro_dns_log_slices);
  // const_bro_http_log_slices = to_const_vector(bro_http_log_slices);
  // const_bgpdump_txt_slices = to_const_vector(bgpdump_txt_slices);
  // const_random_slices = to_const_vector(random_slices);
  const_ascending_integers_slices = to_const_vector(ascending_integers_slices);
  const_alternating_integers_slices
    = to_const_vector(alternating_integers_slices);
  auto to_events = [](const auto& slices) {
    std::vector<event> result;
    for (auto& slice : slices) {
      auto xs = slice->rows_to_events();
      std::move(xs.begin(), xs.end(), std::back_inserter(result));
    }
    return result;
  };
#define SANITY_CHECK(event_vec, slice_vec)                                     \
  {                                                                            \
    auto flat_log = to_events(slice_vec);                                      \
    REQUIRE_EQUAL(event_vec.size(), flat_log.size());                          \
    for (size_t i = 0; i < event_vec.size(); ++i) {                            \
      if (flatten(event_vec[i]) != flat_log[i]) {                              \
        FAIL(#event_vec << " != " << #slice_vec);                              \
      }                                                                        \
    }                                                                          \
  }
  SANITY_CHECK(bro_conn_log, const_bro_conn_log_slices);
  //SANITY_CHECK(bro_dns_log, const_bro_dns_log_slices);
  //SANITY_CHECK(bro_http_log, const_bro_http_log_slices);
  //SANITY_CHECK(bgpdump_txt, const_bgpdump_txt_slices);
  //SANITY_CHECK(random, const_random_slices);
}

} // namespace fixtures
<|endoftext|>


<commit_before>/*
 * tk2tc.cpp
 *
 *  Created on: Nov 20, 2012
 *      Author: partio
 */

#include "tk2tc.h"
#include "plugin_factory.h"
#include "logger_factory.h"
#include <boost/lexical_cast.hpp>
#include <boost/thread.hpp>

#define HIMAN_AUXILIARY_INCLUDE

#include "fetcher.h"
#include "writer.h"
#include "neons.h"
#include "pcuda.h"

#undef HIMAN_AUXILIARY_INCLUDE

#ifdef DEBUG
#include "timer_factory.h"
#endif

using namespace std;
using namespace himan::plugin;

#ifdef HAVE_CUDA
namespace himan
{
namespace plugin
{
namespace tk2tc_cuda
{
void doCuda(const float* Tin, float* Tout, size_t N, unsigned short deviceIndex);
}
}
}
#endif

tk2tc::tk2tc() : itsUseCuda(false)
{
    itsClearTextFormula = "Tc = Tk - 273.15";

    itsLogger = unique_ptr<logger> (logger_factory::Instance()->GetLog("tk2tc"));
}

void tk2tc::Process(std::shared_ptr<configuration> theConfiguration)
{

    shared_ptr<plugin::pcuda> c = dynamic_pointer_cast<plugin::pcuda> (plugin_factory::Instance()->Plugin("pcuda"));

    if (c->HaveCuda())
    {
        string msg = "I possess the powers of CUDA";

        if (!theConfiguration->UseCuda())
        {
            msg += ", but I won't use them";
        }
        else
        {
            msg += ", and I'm not afraid to use them";
            itsUseCuda = true;
        }

        itsLogger->Info(msg);

    }

    // Get number of threads to use

    unsigned short threadCount = ThreadCount(theConfiguration->ThreadCount());

    boost::thread_group g;

    /*
     * The target information is parsed from the configuration file.
     */

    shared_ptr<info> theTargetInfo = theConfiguration->Info();

    /*
     * Get producer information from neons if whole_file_write is false.
     */

    if (!theConfiguration->WholeFileWrite())
    {
        shared_ptr<plugin::neons> n = dynamic_pointer_cast<plugin::neons> (plugin_factory::Instance()->Plugin("neons"));

        map<string,string> prodInfo = n->ProducerInfo(theTargetInfo->Producer().Id());

        if (prodInfo.size())
        {
            producer prod(theTargetInfo->Producer().Id());

            prod.Process(boost::lexical_cast<long> (prodInfo["process"]));
            prod.Centre(boost::lexical_cast<long> (prodInfo["centre"]));
            prod.Name(prodInfo["name"]);

            theTargetInfo->Producer(prod);
        }

    }

    /*
     * Set target parameter to potential temperature
     * - name T-C
     * - univ_id 4
     * - grib2 descriptor 0'00'000
     *
     * We need to specify grib and querydata parameter information
     * since we don't know which one will be the output format.
     *
     */

    vector<param> theParams;

    param theRequestedParam("T-C", 4);

    theRequestedParam.GribDiscipline(0);
    theRequestedParam.GribCategory(0);
    theRequestedParam.GribParameter(0);

    theParams.push_back(theRequestedParam);

    theTargetInfo->Params(theParams);

    /*
     * Create data structures.
     */

    theTargetInfo->Create();

    /*
     * Initialize parent class functions for dimension handling
     */

    Dimension(theConfiguration->LeadingDimension());
    FeederInfo(theTargetInfo->Clone());
    FeederInfo()->Param(theRequestedParam);

    /*
     * Each thread will have a copy of the target info.
     */

    vector<shared_ptr<info> > theTargetInfos;

    theTargetInfos.resize(threadCount);

    for (size_t i = 0; i < threadCount; i++)
    {

        itsLogger->Info("Thread " + boost::lexical_cast<string> (i + 1) + " starting");

        theTargetInfos[i] = theTargetInfo->Clone();

        boost::thread* t = new boost::thread(&tk2tc::Run,
                                             this,
                                             theTargetInfos[i],
                                             theConfiguration,
                                             i + 1);

        g.add_thread(t);

    }

    g.join_all();

    if (theConfiguration->WholeFileWrite())
    {

        shared_ptr<writer> theWriter = dynamic_pointer_cast <writer> (plugin_factory::Instance()->Plugin("writer"));

        theTargetInfo->FirstTime();
        string theOutputFile = "himan_" + theTargetInfo->Time().OriginDateTime()->String("%Y%m%d%H");
        theWriter->ToFile(theTargetInfo, theConfiguration->OutputFileType(), false, theOutputFile);

    }

}

void tk2tc::Run(shared_ptr<info> myTargetInfo,
                shared_ptr<const configuration> theConfiguration,
                unsigned short theThreadIndex)
{

    while (AdjustLeadingDimension(myTargetInfo))
    {
        Calculate(myTargetInfo, theConfiguration, theThreadIndex);
    }
}

/*
 * Calculate()
 *
 * This function does the actual calculation.
 */

void tk2tc::Calculate(shared_ptr<info> myTargetInfo,
                      shared_ptr<const configuration> theConfiguration,
                      unsigned short theThreadIndex)
{

    shared_ptr<fetcher> theFetcher = dynamic_pointer_cast <fetcher> (plugin_factory::Instance()->Plugin("fetcher"));

    // Required source parameters

    param TParam("T-K");

    unique_ptr<logger> myThreadedLogger = std::unique_ptr<logger> (logger_factory::Instance()->GetLog("tpotThread #" + boost::lexical_cast<string> (theThreadIndex)));

    ResetNonLeadingDimension(myTargetInfo);

    myTargetInfo->FirstParam();

    while (AdjustNonLeadingDimension(myTargetInfo))
    {

        myThreadedLogger->Debug("Calculating time " + myTargetInfo->Time().ValidDateTime()->String("%Y%m%d%H") +
                                " level " + boost::lexical_cast<string> (myTargetInfo->Level().Value()));

        myTargetInfo->Data()->Resize(theConfiguration->Ni(), theConfiguration->Nj());

        // Source info for T

        shared_ptr<info> TInfo;

        try
        {
        	TInfo = theFetcher->Fetch(theConfiguration,
                                 myTargetInfo->Time(),
                                 myTargetInfo->Level(),
                                 TParam);

        	assert(TInfo->Param().Unit() == kK);

        }
        catch (HPExceptionType e)
        {
			switch (e)
			{
				case kFileDataNotFound:
					itsLogger->Warning("Skipping step " + boost::lexical_cast<string> (myTargetInfo->Time().Step()) + ", level " + boost::lexical_cast<string> (myTargetInfo->Level().Value()));
					myTargetInfo->Data()->Fill(kFloatMissing);
					continue;
					break;

				default:
					throw runtime_error(ClassName() + ": Unable to proceed");
					break;
			}
        }

        int missingCount = 0;
        int count = 0;

    	shared_ptr<NFmiGrid> targetGrid = myTargetInfo->ToNewbaseGrid();
    	shared_ptr<NFmiGrid> TGrid = TInfo->ToNewbaseGrid();

        bool equalGrids = myTargetInfo->GridAndAreaEquals(TInfo);

#ifdef HAVE_CUDA

        //if (itsUseCuda && equalGrids)
        if (itsUseCuda && equalGrids && theThreadIndex == 1)
        {
            size_t N = TGrid->Size();

            float* TOut = new float[N];

            tk2tc_cuda::doCuda(TGrid->DataPool()->Data(), TOut, N, theThreadIndex-1);

            double *data = new double[N];

            for (size_t i = 0; i < N; i++)
            {
                data[i] = static_cast<float> (TOut[i]);

                if (data[i] == kFloatMissing)
                {
                    missingCount++;
                }

                count++;
            }

            myTargetInfo->Data()->Set(data, N);

            delete [] data;
            delete [] TOut;

        }
        else
        {

#else
        if (true)
        {
#endif

            assert(targetGrid->Size() == myTargetInfo->Data()->Size());

            myTargetInfo->ResetLocation();

            targetGrid->Reset();

#ifdef DEBUG
            unique_ptr<timer> t = unique_ptr<timer> (timer_factory::Instance()->GetTimer());
            t->Start();
#endif

            while (myTargetInfo->NextLocation() && targetGrid->Next())
            {

                count++;

                double T = kFloatMissing;

                InterpolateToPoint(targetGrid, TGrid, equalGrids, T);

                if (T == kFloatMissing)
                {
                    missingCount++;

                    myTargetInfo->Value(kFloatMissing);
                    continue;
                }

                double TC = T + 273.15;

                if (!myTargetInfo->Value(TC))
                {
                    throw runtime_error(ClassName() + ": Failed to set value to matrix");
                }
            }

#ifdef DEBUG
            t->Stop();
            itsLogger->Debug("Calculation took " + boost::lexical_cast<string> (t->GetTime()) + " microseconds on CPU");
#endif

        }

        /*
         * Now we are done for this level
         *
         * Clone info-instance to writer since it might change our descriptor places
         */

        myThreadedLogger->Info("Missing values: " + boost::lexical_cast<string> (missingCount) + "/" + boost::lexical_cast<string> (count));

        if (!theConfiguration->WholeFileWrite())
        {
            shared_ptr<writer> theWriter = dynamic_pointer_cast <writer> (plugin_factory::Instance()->Plugin("writer"));

            theWriter->ToFile(myTargetInfo->Clone(), theConfiguration->OutputFileType(), true);
        }
    }
}
<commit_msg>Fix calculation<commit_after>/*
 * tk2tc.cpp
 *
 *  Created on: Nov 20, 2012
 *      Author: partio
 */

#include "tk2tc.h"
#include "plugin_factory.h"
#include "logger_factory.h"
#include <boost/lexical_cast.hpp>
#include <boost/thread.hpp>

#define HIMAN_AUXILIARY_INCLUDE

#include "fetcher.h"
#include "writer.h"
#include "neons.h"
#include "pcuda.h"

#undef HIMAN_AUXILIARY_INCLUDE

#ifdef DEBUG
#include "timer_factory.h"
#endif

using namespace std;
using namespace himan::plugin;

#ifdef HAVE_CUDA
namespace himan
{
namespace plugin
{
namespace tk2tc_cuda
{
void doCuda(const float* Tin, float* Tout, size_t N, unsigned short deviceIndex);
}
}
}
#endif

tk2tc::tk2tc() : itsUseCuda(false)
{
    itsClearTextFormula = "Tc = Tk - 273.15";

    itsLogger = unique_ptr<logger> (logger_factory::Instance()->GetLog("tk2tc"));
}

void tk2tc::Process(std::shared_ptr<configuration> theConfiguration)
{

    shared_ptr<plugin::pcuda> c = dynamic_pointer_cast<plugin::pcuda> (plugin_factory::Instance()->Plugin("pcuda"));

    if (c->HaveCuda())
    {
        string msg = "I possess the powers of CUDA";

        if (!theConfiguration->UseCuda())
        {
            msg += ", but I won't use them";
        }
        else
        {
            msg += ", and I'm not afraid to use them";
            itsUseCuda = true;
        }

        itsLogger->Info(msg);

    }

    // Get number of threads to use

    unsigned short threadCount = ThreadCount(theConfiguration->ThreadCount());

    boost::thread_group g;

    /*
     * The target information is parsed from the configuration file.
     */

    shared_ptr<info> theTargetInfo = theConfiguration->Info();

    /*
     * Get producer information from neons if whole_file_write is false.
     */

    if (!theConfiguration->WholeFileWrite())
    {
        shared_ptr<plugin::neons> n = dynamic_pointer_cast<plugin::neons> (plugin_factory::Instance()->Plugin("neons"));

        map<string,string> prodInfo = n->ProducerInfo(theTargetInfo->Producer().Id());

        if (prodInfo.size())
        {
            producer prod(theTargetInfo->Producer().Id());

            prod.Process(boost::lexical_cast<long> (prodInfo["process"]));
            prod.Centre(boost::lexical_cast<long> (prodInfo["centre"]));
            prod.Name(prodInfo["name"]);

            theTargetInfo->Producer(prod);
        }

    }

    /*
     * Set target parameter to potential temperature
     * - name T-C
     * - univ_id 4
     * - grib2 descriptor 0'00'000
     *
     * We need to specify grib and querydata parameter information
     * since we don't know which one will be the output format.
     *
     */

    vector<param> theParams;

    param theRequestedParam("T-C", 4);

    theRequestedParam.GribDiscipline(0);
    theRequestedParam.GribCategory(0);
    theRequestedParam.GribParameter(0);

    theParams.push_back(theRequestedParam);

    theTargetInfo->Params(theParams);

    /*
     * Create data structures.
     */

    theTargetInfo->Create();

    /*
     * Initialize parent class functions for dimension handling
     */

    Dimension(theConfiguration->LeadingDimension());
    FeederInfo(theTargetInfo->Clone());
    FeederInfo()->Param(theRequestedParam);

    /*
     * Each thread will have a copy of the target info.
     */

    vector<shared_ptr<info> > theTargetInfos;

    theTargetInfos.resize(threadCount);

    for (size_t i = 0; i < threadCount; i++)
    {

        itsLogger->Info("Thread " + boost::lexical_cast<string> (i + 1) + " starting");

        theTargetInfos[i] = theTargetInfo->Clone();

        boost::thread* t = new boost::thread(&tk2tc::Run,
                                             this,
                                             theTargetInfos[i],
                                             theConfiguration,
                                             i + 1);

        g.add_thread(t);

    }

    g.join_all();

    if (theConfiguration->WholeFileWrite())
    {

        shared_ptr<writer> theWriter = dynamic_pointer_cast <writer> (plugin_factory::Instance()->Plugin("writer"));

        theTargetInfo->FirstTime();
        string theOutputFile = "himan_" + theTargetInfo->Time().OriginDateTime()->String("%Y%m%d%H");
        theWriter->ToFile(theTargetInfo, theConfiguration->OutputFileType(), false, theOutputFile);

    }

}

void tk2tc::Run(shared_ptr<info> myTargetInfo,
                shared_ptr<const configuration> theConfiguration,
                unsigned short theThreadIndex)
{

    while (AdjustLeadingDimension(myTargetInfo))
    {
        Calculate(myTargetInfo, theConfiguration, theThreadIndex);
    }
}

/*
 * Calculate()
 *
 * This function does the actual calculation.
 */

void tk2tc::Calculate(shared_ptr<info> myTargetInfo,
                      shared_ptr<const configuration> theConfiguration,
                      unsigned short theThreadIndex)
{

    shared_ptr<fetcher> theFetcher = dynamic_pointer_cast <fetcher> (plugin_factory::Instance()->Plugin("fetcher"));

    // Required source parameters

    param TParam("T-K");

    unique_ptr<logger> myThreadedLogger = std::unique_ptr<logger> (logger_factory::Instance()->GetLog("tpotThread #" + boost::lexical_cast<string> (theThreadIndex)));

    ResetNonLeadingDimension(myTargetInfo);

    myTargetInfo->FirstParam();

    while (AdjustNonLeadingDimension(myTargetInfo))
    {

        myThreadedLogger->Debug("Calculating time " + myTargetInfo->Time().ValidDateTime()->String("%Y%m%d%H") +
                                " level " + boost::lexical_cast<string> (myTargetInfo->Level().Value()));

        myTargetInfo->Data()->Resize(theConfiguration->Ni(), theConfiguration->Nj());

        // Source info for T

        shared_ptr<info> TInfo;

        try
        {
        	TInfo = theFetcher->Fetch(theConfiguration,
                                 myTargetInfo->Time(),
                                 myTargetInfo->Level(),
                                 TParam);

        	assert(TInfo->Param().Unit() == kK);

        }
        catch (HPExceptionType e)
        {
			switch (e)
			{
				case kFileDataNotFound:
					itsLogger->Warning("Skipping step " + boost::lexical_cast<string> (myTargetInfo->Time().Step()) + ", level " + boost::lexical_cast<string> (myTargetInfo->Level().Value()));
					myTargetInfo->Data()->Fill(kFloatMissing);
					continue;
					break;

				default:
					throw runtime_error(ClassName() + ": Unable to proceed");
					break;
			}
        }

        int missingCount = 0;
        int count = 0;

    	shared_ptr<NFmiGrid> targetGrid = myTargetInfo->ToNewbaseGrid();
    	shared_ptr<NFmiGrid> TGrid = TInfo->ToNewbaseGrid();

        bool equalGrids = myTargetInfo->GridAndAreaEquals(TInfo);

#ifdef HAVE_CUDA

        //if (itsUseCuda && equalGrids)
        if (itsUseCuda && equalGrids && theThreadIndex == 1)
        {
            size_t N = TGrid->Size();

            float* TOut = new float[N];

            tk2tc_cuda::doCuda(TGrid->DataPool()->Data(), TOut, N, theThreadIndex-1);

            double *data = new double[N];

            for (size_t i = 0; i < N; i++)
            {
                data[i] = static_cast<float> (TOut[i]);

                if (data[i] == kFloatMissing)
                {
                    missingCount++;
                }

                count++;
            }

            myTargetInfo->Data()->Set(data, N);

            delete [] data;
            delete [] TOut;

        }
        else
        {

#else
        if (true)
        {
#endif

            assert(targetGrid->Size() == myTargetInfo->Data()->Size());

            myTargetInfo->ResetLocation();

            targetGrid->Reset();

#ifdef DEBUG
            unique_ptr<timer> t = unique_ptr<timer> (timer_factory::Instance()->GetTimer());
            t->Start();
#endif

            while (myTargetInfo->NextLocation() && targetGrid->Next())
            {

                count++;

                double T = kFloatMissing;

                InterpolateToPoint(targetGrid, TGrid, equalGrids, T);

                if (T == kFloatMissing)
                {
                    missingCount++;

                    myTargetInfo->Value(kFloatMissing);
                    continue;
                }

                double TC = T - 273.15;

                if (!myTargetInfo->Value(TC))
                {
                    throw runtime_error(ClassName() + ": Failed to set value to matrix");
                }
            }

#ifdef DEBUG
            t->Stop();
            itsLogger->Debug("Calculation took " + boost::lexical_cast<string> (t->GetTime()) + " microseconds on CPU");
#endif

        }

        /*
         * Now we are done for this level
         *
         * Clone info-instance to writer since it might change our descriptor places
         */

        myThreadedLogger->Info("Missing values: " + boost::lexical_cast<string> (missingCount) + "/" + boost::lexical_cast<string> (count));

        if (!theConfiguration->WholeFileWrite())
        {
            shared_ptr<writer> theWriter = dynamic_pointer_cast <writer> (plugin_factory::Instance()->Plugin("writer"));

            theWriter->ToFile(myTargetInfo->Clone(), theConfiguration->OutputFileType(), true);
        }
    }
}
<|endoftext|>


<commit_before>/*
 * Website:
 *      https://github.com/wo3kie/dojo
 *
 * Author:
 *      Lukasz Czerwinski
 *
 * Compilation:
 *      g++ --std=c++11 fdm.cpp -o fdm
 *
 * Usage:
 *      $ ./fmd
 */

 /*
  * Forward difference:     df(x)/dx ~ (f(x+h) - f(x))/h
  * Backward difference:    df(x)/dx ~ (f(x) - f(x-h))/h
  * Centered difference:    df(x)/dx ~ (f(x+h) - f(x-h))/2*h
  *
  * Centered difference:    d2f(x, t)/dx2 ~ (f(x+h, t) - 2*f(x, t) + f(x-h, t))/h^2
  */

  /*
   * Explicit Forward Difference Method
   *
   * The heat equation, df(x, t)/dt = D*d2f(x, t)/dx2
   * D - diffusion coefficient,     eg.: D=1
   * x - space, a <= x <= b,        eg.: 0 <= x <= X
   * t - time, t >= 0,              eg.: 0 <= t <= T
   * f(x, 0) = initial condition,   eg.: f(X, 0) = sin(2*pi*x) ^ 2
   * f(a, t) = boundary condition,  eg.: f(0, T) = 0
   * f(b, t) = boundary condition,  eg.: f(1, T) = 0
   *
   * (f(x, t+h) - f(x, t))/h = D*(f(x+H, t) - 2*f(x, t) + f(x-H, t))/H^2                     => / *h
   * f(x, t+h) - f(x, t) = D*h/H^2*(f(x+H, t) - 2*f(x, t) + f(x-H, t))                       =>
   * f(x, t+h) = f(x, t) + D*h/H^2*(f(x+H, t) - 2*f(x, t) + f(x-H, t))                       =>
   * f(x, t+h) = f(x, t) * s*f(x+H, t) - 2*s*f(x, t) + s*f(x-H, t), s=D*h/H^2                =>
   * f(x, t+h) = s*f(x-H, t) + (1-2*s)*f(x, t) + s*f(x+H, t)                                 =>
   * f[x][t+1] = s*f[x-1][t] + (1-2*s)*f[x][t] + s*f[x+1][t]                                 =>
   *
   *
   * f[1][t+1] = s*f[0][t] + (1-2*s)*f[1][t] + s*f[2][t]
   * f[2][t+1] = s*f[1][t] + (1-2*s)*f[2][t] + s*f[3][t]
   * ...
   * f[X-1][t+1] = s*f[X-2][t] + (1-2*s)*f[X-1][t] + s*f[X][t]                                 =>
   *
   *
   * f[1][t+1]       = (1-2*s)*f[1][t] +       s*f[2][t] +               0 + s *     f[0][t]
   * f[2][t+1]       =       s*f[1][t] + (1-2*s)*f[2][t] +       s*f[3][t]
   * ...
   * f[X-1][t+1]     =                     s*f[X-2][t] + (1-2*s)*f[X-1][t] + s *     f[X][t]   =>
   *
   *
   *
   * |  f[1][t]  |   | 1-2*s,     s,     0, ...      0 |   |   f[1][t-1] |       | f[0][t-1] |
   * |  f[2][t]  |   |     s, 1-2*s,     s, ...      0 |   |   f[2][t-1] |       |     0     |
   * |  f[3][t]  |   |     0,     s, 1-2*s, ...      . |   |     .       |       |     .     |
   * |      .    | = |     .   .       .    .        . | * |     .       | + s * |     .     |
   * |      .    |   |     .    .       .    .       . |   |     .       |       |     .     |
   * |      .    |   |     .     .       .    .      s |   | f[X-2][t-1] |       |     0     |
   * | f[X-1][t] |   |     0,   ...      0,   s, 1-2*s |   | f[X-1][t-1] |       | f[X][t-1] |
   *
   */

#include <cassert>
#include <cmath>

void fdm_forward(){
    constexpr int const X = 10;
    constexpr int const T = 10;

    double f[X][T] = { 0 };

    // initial condition
    for(int x = 0; x < X; ++x){
        f[x][0] = sin(2 * M_PI * x) * sin(2 * M_PI * x);
    }

    // boundary condition
    for(int t = 0; t < T; ++t){
        f[0][t] = 0;
        f[9][t] = 0;
    }

    constexpr double const D = 1.0;
    constexpr double const H = 0.1;
    constexpr double const h = 0.004;
    constexpr double const s = D * h / H / H;

    static_assert(s <= 0.5, "");

    // A

    double S[X-2][X-2] = { 0 };

    for(int x = 0; x < X-2; ++x){
        S[x][x] = 1 - 2 * s;
    }

    for(int x = 0; x < X-2-1; ++x){
        S[x][x+1] = s;
    }

    for(int x = 1; x < X-2; ++x){
        S[x][x-1] = s;
    }

    for(int ti = 1; ti < T; ++ti){
        for(int fR = 1; fR < X-1; ++fR){
            for(int sC = 0; sC < X-2; ++sC){
                f[fR][ti] += A[fR-1][sC] * f[fR][ti-1];
            }

            if(fR == 1){
                f[fR][ti] += S * f[fR-1][ti-1];
            }

            if(fR == X-2){
                f[fR][ti] += S * f[fR+1][ti-1];
            }
        }
    }
}

int main(){
    fdm_forward();
}<commit_msg>fdm.cpp<commit_after>/*
 * Website:
 *      https://github.com/wo3kie/dojo
 *
 * Author:
 *      Lukasz Czerwinski
 *
 * Compilation:
 *      g++ --std=c++11 fdm.cpp -o fdm
 *
 * Usage:
 *      $ ./fmd | gnuplot5 -p
 */

 /*
  * Forward difference:     df(x)/dx ~ (f(x+h) - f(x))/h
  * Backward difference:    df(x)/dx ~ (f(x) - f(x-h))/h
  * Centered difference:    df(x)/dx ~ (f(x+h) - f(x-h))/2*h
  *
  * Centered difference:    d2f(x, t)/dx2 ~ (f(x+h, t) - 2*f(x, t) + f(x-h, t))/h^2
  */

#include <cassert>
#include <cmath>
#include <iomanip>
#include <iostream>

template<int N, int M>
void print(double (&f)[N][M]){
    for(int n = 0; n < N; ++n){
        std::cout << '[';

        for(int m = 0; m < M; ++m){
            std::cout << std::setprecision(5) << f[n][m] << ' ';
        }

        std::cout << "]\n";
    }

    std::cout << '\n';
}

void fdm_forward(){
    /*
    * Explicit Forward Difference Method
    *
    * The heat equation, df(x, t)/dt = D*d2f(x, t)/dx2
    * D - diffusion coefficient,     eg.: D=1
    * x - space,                     eg.: 0 <= x <= X
    * t - time,                      eg.: 0 <= t <= T
    * f(x, 0) = initial condition,   eg.: f(X, 0) = sin(2*pi*x) ^ 2
    * f(a, t) = boundary condition,  eg.: f(0, T) = 0
    * f(b, t) = boundary condition,  eg.: f(1, T) = 0
    *
    * (f(x, t+dt) - f(x, t))/dt = D*(f(x+dx, t) - 2*f(x, t) + f(x-dx, t))/dx^2              => / *dt
    * f(x, t+dt) - f(x, t) = D*dt/dx^2*(f(x+dx, t) - 2*f(x, t) + f(x-dx, t))                =>
    * f(x, t+dt) = f(x, t) + D*dt/dx^2*(f(x+dx, t) - 2*f(x, t) + f(x-dx, t))                =>
    * f(x, t+dt) = f(x, t) * s*f(x+dx, t) - 2*s*f(x, t) + s*f(x-dx, t), s=D*dt/dx^2         =>
    * f(x, t+dt) = s*f(x-dx, t) + (1-2*s)*f(x, t) + s*f(x+dx, t)                            =>
    * f[x][t+1]  = s*f[x-1][t] + (1-2*s)*f[x][t] + s*f[x+1][t]                              =>
    *
    *
    * f[1][t]   = s*f[0][t-1] + (1-2*s)*f[1][t-1] + s*f[2][t-1]
    * f[2][t]   = s*f[1][t-1] + (1-2*s)*f[2][t-1] + s*f[3][t-1]
    * ...
    * f[X-1][t] = s*f[X-2][t-1] + (1-2*s)*f[X-1][t-1] + s*f[X][t-1]                         =>
    *
    *
    * |  f[1][t]  |   | 1-2*s,     s,     0, ...      0 |   |   f[1][t-1] |       | f[0][t-1] |
    * |  f[2][t]  |   |     s, 1-2*s,     s, ...      0 |   |   f[2][t-1] |       |     0     |
    * |  f[3][t]  |   |     0,     s, 1-2*s, ...      . |   |       .     |       |     .     |
    * |     .     | = |     .   .       .    .        . | * |       .     | + s * |     .     |
    * |     .     |   |     .    .       .    .       . |   |       .     |       |     .     |
    * |     .     |   |     .     .       .    .      s |   | f[X-2][t-1] |       |     0     |
    * | f[X-1][t] |   |     0,   ...      0,   s, 1-2*s |   | f[X-1][t-1] |       | f[X][t-1] |
    *
    */

    constexpr double const D = 1.0;
    constexpr double const dx = 0.1;
    constexpr double const dt = 0.004;
    constexpr double const s = D * dt / dx / dx;

    //static_assert(s <= 0.5, "");

    constexpr int const X = 1 + 1 / dx;
    constexpr int const T = 1 + 1 / dt;

    double f[X][T] = { 0 };
    double S[X-2][X-2] = { 0 };

    for(int x = 0; x < X; ++x){
        f[x][0] = sin(2 * M_PI * x * dx) * sin(2 * M_PI * x * dx);
    }

    for(int t = 0; t < T; ++t){
        f[0][t] = 0;
        f[9][t] = 0;
    }

    for(int x = 0; x < X-2; ++x){
        S[x][x] = 1 - 2 * s;
    }

    for(int x = 0; x < X-2-1; ++x){
        S[x][x+1] = s;
    }

    for(int x = 1; x < X-2; ++x){
        S[x][x-1] = s;
    }

    for(int ti = 1; ti < T; ++ti){
        f[1][ti] += s * f[0][ti-1];

        for(int fR = 1; fR < X-1; ++fR){
            for(int sC = 0; sC < X-2; ++sC){
                f[fR][ti] += S[fR-1][sC] * f[sC+1][ti-1];
            }
        }

        f[X-2][ti] += s * f[X-1][ti-1];
    }

    {
        std::cout
            << "# gnuplot 5.1 file script\n"
            << "$data << EOD\n";

        for(int x = 0; x < X; ++x){
            for(int t = 0; t < T; ++t){
                std::cout << (x*dx) << " " << (t*dt) << " " << std::setprecision(5) << f[x][t] << '\n';
            }
        }

        std::cout
            << "EOD\n"
            << "set xrange [0:1]\n"
            << "set xlabel \"X\"\n"
            << "set yrange [0:1]\n"
            << "set ylabel \"Time\"\n"
            << "set zrange [0:0.2]\n"
            << "set zlabel \"Temp\"\n"
            << "set dgrid3d 50, 50\n"
            << "set hidden3d\n"
            << "splot \"$data\" with lines\n";
    }
}

int main(){
    fdm_forward();
}
<|endoftext|>


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

#include <algorithm>
#include <cctype>
#include <cassert>
#include <cstring>

namespace bn
{

template<class Iter1, class Iter2>
void encode_b16(Iter1 start, Iter1 end, Iter2 out);

template<class Iter1, class Iter2>
void encode_b32(Iter1 start, Iter1 end, Iter2 out);

template<class Iter1, class Iter2>
void encode_b64(Iter1 start, Iter1 end, Iter2 out);

template<class Iter1, class Iter2>
void decode_b16(Iter1 start, Iter1 end, Iter2 out);

template<class Iter1, class Iter2>
void decode_b32(Iter1 start, Iter1 end, Iter2 out);

template<class Iter1, class Iter2>
void decode_b64(Iter1 start, Iter1 end, Iter2 out);

namespace impl
{

const char Error = -1;

namespace {

inline char extract_partial_bits(char value, size_t start_bit, size_t bits_count)
{
    assert(start_bit + bits_count < 8);
    // shift extracted bits to the beginning of the byte
    char t1 = value >> (8 - bits_count - start_bit);
    // mask out bits on the left
    char t2 = t1 & ~(0xff << bits_count);
    return t2;
}

inline char extract_overlapping_bits(char previous, char next, size_t start_bit, size_t bits_count)
{
    assert(start_bit + bits_count < 16);
    size_t bits_count_in_previous = 8 - start_bit;
    size_t bits_count_in_next = bits_count - bits_count_in_previous;
    char t1 = previous << bits_count_in_next;
    char t2 = next >> (8 - bits_count_in_next) & ~(0xff << bits_count_in_next) ;
    return (t1 | t2) & ~(0xff << bits_count);
}

}

struct b16_conversion_traits
{
    static size_t group_length()
    {
       return 4;
    }

    static char encode(unsigned int index)
    {
        static const char* const dictionary = "0123456789ABCDEF";
        assert(index < strlen(dictionary));
        return dictionary[index];
    }

    static char decode(char c)
    {
        if (c >= '0' && c <= '9') {
            return c - '0';
        } else if (c >= 'A' && c <= 'F') {
            return c - 'A' + 10;
        }
        return Error;
    }
};

struct b32_conversion_traits
{
    static size_t group_length()
    {
       return 5;
    }

    static char encode(unsigned int index)
    {
        static const char * dictionary = "ABCDEFGHIJKLMNOPQRSTUVWXYZ234567";
        assert(index < strlen(dictionary));
        return dictionary[index];
    }

    static char decode(char c)
    {
        if (c >= 'A' && c <= 'Z') {
            return c - 'A';
        } else if (c >= '2' && c <= '7') {
            return c - '2' + 26;
        }
        return Error;
    }
};

struct b64_conversion_traits
{
    static size_t group_length()
    {
       return 6;
    }

    static char encode(unsigned int index)
    {
        static const char* const dictionary = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
        assert(index < strlen(dictionary));
        return dictionary[index];
    }

    static char decode(char c)
    {
        const int alph_len = 26;
        if (c >= 'A' && c <= 'Z') {
            return c - 'A';
        } else if (c >= 'a' && c <= 'z') {
            return c - 'a' + alph_len * 1;
        } else if (c >= '0' && c <= '9') {
            return c - '0' + alph_len * 2;
        } else if (c == '+') {
            return c - '+' + alph_len * 2 + 10;
        } else if (c == '/') {
            return c - '/' + alph_len * 2 + 11;
        }
        return Error;
    }
};

template<class ConversionTraits, class Iter1, class Iter2>
void decode(Iter1 start, Iter1 end, Iter2 out)
{
    Iter1 iter = start;
    size_t output_current_bit = 0;
    char buffer = 0;

    while (iter != end) {
        if (std::isspace(*iter)) {
            ++iter;
            continue;
        }
        char value = ConversionTraits::decode(*iter);
        if (value == Error) {
            // malformed data, but let's go on...
            ++iter;
            continue;
        }
        size_t bits_in_current_byte = std::min<size_t>(output_current_bit + ConversionTraits::group_length(), 8) - output_current_bit;
        if (bits_in_current_byte == ConversionTraits::group_length()) {
            // the value fits within current byte, so we can extract it directly
            buffer |= value << (8 - output_current_bit - ConversionTraits::group_length());
            output_current_bit += ConversionTraits::group_length();
            // check if we filled up current byte completely; in such case we flush output and continue
            if (output_current_bit == 8) {
                *out++ = buffer;
                buffer = 0;
                output_current_bit = 0;
            }
        } else {
            // the value spans across the current and the next byte
            size_t bits_in_next_byte = ConversionTraits::group_length() - bits_in_current_byte;
            // fill the current byte and flush it to our output
            buffer |= value >> bits_in_next_byte;
            *out++ = buffer;
            buffer = 0;
            // save the remainder of our value in the buffer; it will be flushed
            // during next iterations
            buffer |= value << (8 - bits_in_next_byte);
            output_current_bit = bits_in_next_byte;
        }
        ++iter;
    }
}

template<class ConversionTraits, class Iter1, class Iter2>
void encode(Iter1 start, Iter1 end, Iter2 out)
{
#if __cplusplus >= 201103 || (defined(_MSC_VER) && _MSC_VER > 1700)
    static_assert(sizeof(*start) == sizeof(char), "only char-size input supported");
#else // compatibility with older C++ without static assertions
    assert(sizeof(*start) == sizeof(char) && "only char-size input supported");
#endif

    Iter1 iter = start;
    size_t start_bit = 0;
    bool has_backlog = false;
    char backlog = 0;

    while (has_backlog || iter != end) {
        if (!has_backlog) {
            if (start_bit + ConversionTraits::group_length() < 8) {
                // the value fits within single byte, so we can extract it
                // directly
                char v = extract_partial_bits(*iter, start_bit, ConversionTraits::group_length());
                *out++ = ConversionTraits::encode(v);
                // since we know that start_bit + ConversionTraits::group_length() < 8 we don't need to go
                // to the next byte
                start_bit += ConversionTraits::group_length();
            } else {
                // our bits are spanning across byte border; we need to keep the
                // starting point and move over to next byte.
                backlog = *iter++;
                has_backlog = true;
            }
        } else {
            // encode value which is made from bits spanning across byte
            // boundary
            char v;
            if (iter == end)
                 v = extract_overlapping_bits(backlog, 0, start_bit, ConversionTraits::group_length());
            else
                 v = extract_overlapping_bits(backlog, *iter, start_bit, ConversionTraits::group_length());
            *out++ = ConversionTraits::encode(v);
            has_backlog = false;
            start_bit = (start_bit + ConversionTraits::group_length()) % 8;
        }
    }
}

} // impl

using namespace bn::impl;

template<class Iter1, class Iter2>
void encode_b16(Iter1 start, Iter1 end, Iter2 out)
{
    encode<b16_conversion_traits>(start, end, out);
}

template<class Iter1, class Iter2>
void encode_b32(Iter1 start, Iter1 end, Iter2 out)
{
    encode<b32_conversion_traits>(start, end, out);
}

template<class Iter1, class Iter2>
void encode_b64(Iter1 start, Iter1 end, Iter2 out)
{
    encode<b64_conversion_traits>(start, end, out);
}

template<class Iter1, class Iter2>
void decode_b16(Iter1 start, Iter1 end, Iter2 out)
{
    decode<b16_conversion_traits>(start, end, out);
}

template<class Iter1, class Iter2>
void decode_b32(Iter1 start, Iter1 end, Iter2 out)
{
    decode<b32_conversion_traits>(start, end, out);
}

template<class Iter1, class Iter2>
void decode_b64(Iter1 start, Iter1 end, Iter2 out)
{
    decode<b64_conversion_traits>(start, end, out);
}

} // bn

#endif // BASEN_HPP
<commit_msg>Silence size_t to char implicit conversion warning.<commit_after>/**
 * base-n, 1.0
 * Copyright (C) 2012 Andrzej Zawadzki (azawadzki@gmail.com)
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 * SOFTWARE.
**/
#ifndef BASEN_HPP
#define BASEN_HPP

#include <algorithm>
#include <cctype>
#include <cassert>
#include <cstring>

namespace bn
{

template<class Iter1, class Iter2>
void encode_b16(Iter1 start, Iter1 end, Iter2 out);

template<class Iter1, class Iter2>
void encode_b32(Iter1 start, Iter1 end, Iter2 out);

template<class Iter1, class Iter2>
void encode_b64(Iter1 start, Iter1 end, Iter2 out);

template<class Iter1, class Iter2>
void decode_b16(Iter1 start, Iter1 end, Iter2 out);

template<class Iter1, class Iter2>
void decode_b32(Iter1 start, Iter1 end, Iter2 out);

template<class Iter1, class Iter2>
void decode_b64(Iter1 start, Iter1 end, Iter2 out);

namespace impl
{

const char Error = -1;

namespace {

inline char extract_partial_bits(char value, size_t start_bit, size_t bits_count)
{
    assert(start_bit + bits_count < 8);
    // shift extracted bits to the beginning of the byte
    char t1 = value >> (8 - bits_count - start_bit);
    // mask out bits on the left
    char t2 = t1 & ~(0xff << bits_count);
    return t2;
}

inline char extract_overlapping_bits(char previous, char next, size_t start_bit, size_t bits_count)
{
    assert(start_bit + bits_count < 16);
    size_t bits_count_in_previous = 8 - start_bit;
    size_t bits_count_in_next = bits_count - bits_count_in_previous;
    char t1 = static_cast<char>(previous << bits_count_in_next);
    char t2 = next >> (8 - bits_count_in_next) & ~(0xff << bits_count_in_next);
    return (t1 | t2) & ~(0xff << bits_count);
}

}

struct b16_conversion_traits
{
    static size_t group_length()
    {
       return 4;
    }

    static char encode(unsigned int index)
    {
        static const char* const dictionary = "0123456789ABCDEF";
        assert(index < strlen(dictionary));
        return dictionary[index];
    }

    static char decode(char c)
    {
        if (c >= '0' && c <= '9') {
            return c - '0';
        } else if (c >= 'A' && c <= 'F') {
            return c - 'A' + 10;
        }
        return Error;
    }
};

struct b32_conversion_traits
{
    static size_t group_length()
    {
       return 5;
    }

    static char encode(unsigned int index)
    {
        static const char * dictionary = "ABCDEFGHIJKLMNOPQRSTUVWXYZ234567";
        assert(index < strlen(dictionary));
        return dictionary[index];
    }

    static char decode(char c)
    {
        if (c >= 'A' && c <= 'Z') {
            return c - 'A';
        } else if (c >= '2' && c <= '7') {
            return c - '2' + 26;
        }
        return Error;
    }
};

struct b64_conversion_traits
{
    static size_t group_length()
    {
       return 6;
    }

    static char encode(unsigned int index)
    {
        static const char* const dictionary = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
        assert(index < strlen(dictionary));
        return dictionary[index];
    }

    static char decode(char c)
    {
        const int alph_len = 26;
        if (c >= 'A' && c <= 'Z') {
            return c - 'A';
        } else if (c >= 'a' && c <= 'z') {
            return c - 'a' + alph_len * 1;
        } else if (c >= '0' && c <= '9') {
            return c - '0' + alph_len * 2;
        } else if (c == '+') {
            return c - '+' + alph_len * 2 + 10;
        } else if (c == '/') {
            return c - '/' + alph_len * 2 + 11;
        }
        return Error;
    }
};

template<class ConversionTraits, class Iter1, class Iter2>
void decode(Iter1 start, Iter1 end, Iter2 out)
{
    Iter1 iter = start;
    size_t output_current_bit = 0;
    char buffer = 0;

    while (iter != end) {
        if (std::isspace(*iter)) {
            ++iter;
            continue;
        }
        char value = ConversionTraits::decode(*iter);
        if (value == Error) {
            // malformed data, but let's go on...
            ++iter;
            continue;
        }
        size_t bits_in_current_byte = std::min<size_t>(output_current_bit + ConversionTraits::group_length(), 8) - output_current_bit;
        if (bits_in_current_byte == ConversionTraits::group_length()) {
            // the value fits within current byte, so we can extract it directly
            buffer |= value << (8 - output_current_bit - ConversionTraits::group_length());
            output_current_bit += ConversionTraits::group_length();
            // check if we filled up current byte completely; in such case we flush output and continue
            if (output_current_bit == 8) {
                *out++ = buffer;
                buffer = 0;
                output_current_bit = 0;
            }
        } else {
            // the value spans across the current and the next byte
            size_t bits_in_next_byte = ConversionTraits::group_length() - bits_in_current_byte;
            // fill the current byte and flush it to our output
            buffer |= value >> bits_in_next_byte;
            *out++ = buffer;
            buffer = 0;
            // save the remainder of our value in the buffer; it will be flushed
            // during next iterations
            buffer |= value << (8 - bits_in_next_byte);
            output_current_bit = bits_in_next_byte;
        }
        ++iter;
    }
}

template<class ConversionTraits, class Iter1, class Iter2>
void encode(Iter1 start, Iter1 end, Iter2 out)
{
#if __cplusplus >= 201103 || (defined(_MSC_VER) && _MSC_VER > 1700)
    static_assert(sizeof(*start) == sizeof(char), "only char-size input supported");
#else // compatibility with older C++ without static assertions
    assert(sizeof(*start) == sizeof(char) && "only char-size input supported");
#endif

    Iter1 iter = start;
    size_t start_bit = 0;
    bool has_backlog = false;
    char backlog = 0;

    while (has_backlog || iter != end) {
        if (!has_backlog) {
            if (start_bit + ConversionTraits::group_length() < 8) {
                // the value fits within single byte, so we can extract it
                // directly
                char v = extract_partial_bits(*iter, start_bit, ConversionTraits::group_length());
                *out++ = ConversionTraits::encode(v);
                // since we know that start_bit + ConversionTraits::group_length() < 8 we don't need to go
                // to the next byte
                start_bit += ConversionTraits::group_length();
            } else {
                // our bits are spanning across byte border; we need to keep the
                // starting point and move over to next byte.
                backlog = *iter++;
                has_backlog = true;
            }
        } else {
            // encode value which is made from bits spanning across byte
            // boundary
            char v;
            if (iter == end)
                 v = extract_overlapping_bits(backlog, 0, start_bit, ConversionTraits::group_length());
            else
                 v = extract_overlapping_bits(backlog, *iter, start_bit, ConversionTraits::group_length());
            *out++ = ConversionTraits::encode(v);
            has_backlog = false;
            start_bit = (start_bit + ConversionTraits::group_length()) % 8;
        }
    }
}

} // impl

using namespace bn::impl;

template<class Iter1, class Iter2>
void encode_b16(Iter1 start, Iter1 end, Iter2 out)
{
    encode<b16_conversion_traits>(start, end, out);
}

template<class Iter1, class Iter2>
void encode_b32(Iter1 start, Iter1 end, Iter2 out)
{
    encode<b32_conversion_traits>(start, end, out);
}

template<class Iter1, class Iter2>
void encode_b64(Iter1 start, Iter1 end, Iter2 out)
{
    encode<b64_conversion_traits>(start, end, out);
}

template<class Iter1, class Iter2>
void decode_b16(Iter1 start, Iter1 end, Iter2 out)
{
    decode<b16_conversion_traits>(start, end, out);
}

template<class Iter1, class Iter2>
void decode_b32(Iter1 start, Iter1 end, Iter2 out)
{
    decode<b32_conversion_traits>(start, end, out);
}

template<class Iter1, class Iter2>
void decode_b64(Iter1 start, Iter1 end, Iter2 out)
{
    decode<b64_conversion_traits>(start, end, out);
}

} // bn

#endif // BASEN_HPP
<|endoftext|>


<commit_before>#include "stdafx.h"
#include "FluidSimulation.h"
#include "glext.h"
#include "Parameter.h"
#include <math.h>

extern float interpolatedParameters[];

FluidSimulation::FluidSimulation() {
    next_ = 0;
}

FluidSimulation::~FluidSimulation() {
}

void FluidSimulation::Init(void) {
    next_ = 1;
    for (int y = 0; y < kTotalHeight; y++) {
        for (int x = 0; x < kTotalWidth; x++) {
            fluid_amount_[1 - next_][y][x] = 0.0f;
            fluid_amount_[next_][y][x] = 0.0f;
        }
    }
    remain_time_ = 0.0f;
    current_time = 0.0;

    // Put some fluid to the left and right
#if 1
    last_sum_fluid = 0.0f;
    for (int y = kTotalHeight / 2 - 20; y < kTotalHeight / 2 + 21; y++) {
        for (int x = 0; x < 80; x++) {
            fluid_amount_[1 - next_][y + 20][x] = 1.0f;
            fluid_amount_[1 - next_][y - 20][kTotalWidth - x - 1] = 1.0f;
            last_sum_fluid += 2.0f;
        }
    }
#else
    last_sum_fluid = 0.0f;
    float cell_fluid = FS_TOTAL_SUM_FLUID / (kTotalHeight * kTotalWidth);
    for (int y = 0; y < kTotalHeight; y++) {
        for (int x = 0; x < kTotalHeight; x++) {
            last_sum_fluid += cell_fluid;
            fluid_amount_[1 - next_][y][x] = cell_fluid;
        }
    }
#endif

    glGenTextures(1, &texture_id_);
    glBindTexture(GL_TEXTURE_2D, texture_id_);
    glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
    glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);

    glTexImage2D(GL_TEXTURE_2D, 0, GL_R8,
        kTotalWidth, kTotalHeight,
        0, GL_RED, GL_FLOAT, fluid_amount_[1 - next_]);
}

GLuint FluidSimulation::GetTexture(void) {
    // Send data to GPU
    glBindTexture(GL_TEXTURE_2D, texture_id_);
    return texture_id_;
}

void FluidSimulation::UpdateTime(float time_difference) {
    time_difference += remain_time_;
    remain_time_ = 0.0f;
    bool did_update = false;

    while (time_difference > FS_UPDATE_STEP) {
        current_time += FS_UPDATE_STEP;
        float time = (float)current_time;
        did_update = true;
        int next = next_;
        float add_fluid = FS_TOTAL_SUM_FLUID - last_sum_fluid;
        add_fluid /= kTotalHeight * kTotalWidth;
        last_sum_fluid = 0.0f;
#if 0
        // Reduce speed due to friction
        for (int y = 0; y < kTotalHeight; y++) {
            for (int x = 0; x < kTotalWidth; x++) {
                fluid_velocity_[1 - next][y][x][0] *= FS_VELOCITY_MULTIPLIER;
                if (fabsf(fluid_velocity_[1 - next][y][x][0]) < 1.e-5f) fluid_velocity_[1 - next][y][x][0] = 0.0f;
                fluid_velocity_[1 - next][y][x][1] *= FS_VELOCITY_MULTIPLIER;
                if (fabsf(fluid_velocity_[1 - next][y][x][1]) < 1.e-5f) fluid_velocity_[1 - next][y][x][0] = 0.0f;
            }
        }

        // Do fluid - pull
        for (int y = 1; y < kTotalHeight - 1; y++) {
            for (int x = 1; x < kTotalWidth - 1; x++) {
                float amount = fluid_amount_[1 - next][y][x];
                float pull_amount = amount - amount * amount;
                if (amount > 1.0f) pull_amount = (1.0f - amount) * FS_PUSH_MULTIPLIER;
                if (amount < 0.0f) pull_amount = -amount;  // Should not happen, still negative fluid --> pull
                pull_amount *= FS_PULL_STRENGTH;
                //if (pull_amount > 0.5f) pull_amount = 0.5f;
                fluid_velocity_[1 - next][y][x + 1][0] -= pull_amount;
                fluid_velocity_[1 - next][y][x - 1][0] += pull_amount;
                fluid_velocity_[1 - next][y + 1][x][1] -= pull_amount;
                fluid_velocity_[1 - next][y - 1][x][1] += pull_amount;
            }
        }

        // Apply trace field
        float yp = -1.0f;
        float x_step = 2.0f / kTotalWidth;
        float y_step = 2.0f / kTotalHeight;
        for (int y = 0; y < kTotalHeight; y++) {
            float xp = -1.0f;
            for (int x = 0; x < kTotalWidth; x++) {
                float adjusted_xp = xp;
                float adjusted_yp = yp;

                adjusted_xp += interpolatedParameters[2] * fabsf(yp) * 0.75f;
                adjusted_xp -= interpolatedParameters[3] * fabsf(yp) * 0.75f;
                adjusted_yp += interpolatedParameters[3] * xp * 0.25f;

                float length = sqrtf(adjusted_xp * adjusted_xp + adjusted_yp * adjusted_yp);
                if (length < 0.0001f) length = 0.0001f;
                float x_normal = adjusted_yp / length;
                float y_normal = -adjusted_xp / length;

                // Circle-pos
                float center_move = length - 0.5f;

                fluid_velocity_[1 - next][y][x][0] -= adjusted_xp * center_move * FS_FIELD_STRENGTH_CENTER;
                fluid_velocity_[1 - next][y][x][1] -= adjusted_yp * center_move * FS_FIELD_STRENGTH_CENTER;

                // Rotation
                fluid_velocity_[1 - next][y][x][0] += FS_FIELD_STRENGTH_ROTATION * x_normal * (1.0f - fabsf(center_move));
                fluid_velocity_[1 - next][y][x][1] += FS_FIELD_STRENGTH_ROTATION * y_normal * (1.0f - fabsf(center_move));

                // Move out of middle
                //fluid_velocity_[1 - next][y][x][0] += 0.01f / (length * length + 0.1f);

                xp += x_step;
            }
            yp += y_step;
        }

        // Copy fluid to next frame
        for (int y = 0; y < kTotalHeight; y++) {
            for (int x = 0; x < kTotalWidth; x++) {
                fluid_amount_[next][y][x] = fluid_amount_[1 - next][y][x] + add_fluid;
                last_sum_fluid += fluid_amount_[next][y][x];
                // TODO: Max fluid speed 1.0?
            }
        }
#endif

        // Copy top row that is not copied otherwise
        for (int x = 0; x < kTotalWidth; x++) {
            fluid_amount_[next][0][x] = fluid_amount_[1 - next][0][x];
        }

        // Actually move the fluid
        float yp = -1.0f;
        float x_step = 2.0f / kTotalWidth;
        float y_step = 2.0f / kTotalHeight;
        for (int y = 0; y < kTotalHeight - 1; y++) {
            float xp = -1.0f;

            // Last row just copy
            fluid_amount_[next][y][kTotalWidth - 1] = fluid_amount_[1 - next][y][kTotalWidth - 1];

            for (int x = 0; x < kTotalWidth - 1; x++) {
                float current_amount = fluid_amount_[1 - next][y][x] + add_fluid;
                float right_amount = fluid_amount_[1 - next][y][x + 1];
                float bottom_amount = fluid_amount_[1 - next][y + 1][x];
                float next_amount = fluid_amount_[next][y][x];
                last_sum_fluid += current_amount;

                // Calculate velocities
                float length = sqrtf(xp * xp + yp * yp);
                if (length < 0.0001f) length = 0.0001f;
                float x_normal = yp / length;
                float y_normal = -xp / length;
                // Circle-pos
                float center_move = length - 0.5f;
                float right_velocity = -xp * center_move * FS_FIELD_STRENGTH_CENTER;
                float down_velocity = -yp * center_move * FS_FIELD_STRENGTH_CENTER;
                // Rotation
                right_velocity += FS_FIELD_STRENGTH_ROTATION * x_normal * (1.0f - fabsf(center_move));
                down_velocity += FS_FIELD_STRENGTH_ROTATION * y_normal * (1.0f - fabsf(center_move));

                // Some middle hill
                float hill_rotation = time * FS_HILL_ROTATION_SPEED;
                //float xp_rot = cos(hill_rotation) * xp - sin(hill_rotation) * yp;
                float yp_rot = sinf(hill_rotation) * xp + cosf(hill_rotation) * yp;
                float line_dist = yp_rot * yp_rot;
                float hill_amount = interpolatedParameters[2] * 0.03f / (line_dist + 0.03f);
                float away_amount = 1.0f * yp_rot * hill_amount;  // goes to linear?
                right_velocity += -sinf(-hill_rotation) * away_amount;
                down_velocity += cosf(-hill_rotation) * away_amount;

                // Tear up
                right_velocity += 0.3f * sinf(yp * 9.f + time) *
                    cosf(xp * (8.f + sinf(time * 0.3f)) - time * 0.7f) * interpolatedParameters[3];
                down_velocity += 0.3f * cosf(yp * (7.f - cosf(time * 0.27f)) - time * 0.9f) *
                    sinf(xp * 5.f + time * 0.6f) * interpolatedParameters[3];

#if 1
                float pull_amount = CalculatePull(current_amount);
                float pull_right = CalculatePull(right_amount);
                float pull_bottom = CalculatePull(bottom_amount);
                right_velocity -= pull_amount - pull_right;
                down_velocity -= pull_amount - pull_bottom;
#else
                float pull_amount = CalculatePull(current_amount);
                right_velocity -= pull_amount;
                down_velocity -= pull_amount;
#endif

                if (right_velocity > 0.5f) right_velocity = 0.5f;
                if (down_velocity > 0.5f) down_velocity = 0.5f;

                // move right
                float move_amount;
                if (right_velocity > 0) {
                    move_amount = right_velocity * current_amount;
                } else {
                    move_amount = right_velocity * right_amount;
                }
                next_amount -= move_amount;
                fluid_amount_[next][y][x + 1] += move_amount;
                // Copy y stuff
                float next_bottom = bottom_amount;
                // move bottom
                if (down_velocity > 0) {
                    move_amount = down_velocity * current_amount;
                } else {
                    move_amount = down_velocity * bottom_amount;
                }
                next_amount -= move_amount;
                next_bottom += move_amount;
                fluid_amount_[next][y + 1][x] = next_bottom;

                // Check for invalid numbers. This thing is done last...
                if (isnan(next_amount) || next_amount < -0.5f || next_amount > 1.5f) {
                    next_amount = current_amount;
                }
                if (fabsf(next_amount) < 1e-7f) next_amount = 0.0f;

                fluid_amount_[next][y][x] = next_amount;

                xp += x_step;
            }

            yp += y_step;
        }

        // Check final row:
        for (int x = 0; x < kTotalWidth; x++) {
            int y = kTotalHeight - 1;
            float next_amount = fluid_amount_[next][y][x];
            if (isnan(next_amount) || next_amount < -0.5f || next_amount > 1.5f) {
                fluid_amount_[next][y][x] = fluid_amount_[1 - next][y][x];
            }
        }

        time_difference -= FS_UPDATE_STEP;
        next_ = 1 - next;
        if (time_difference > 0.2f) time_difference = 0.0f;
    }

    if (did_update) {
        glBindTexture(GL_TEXTURE_2D, texture_id_);
        glTexSubImage2D(GL_TEXTURE_2D, 0,
            0, 0, kTotalWidth, kTotalHeight,
            GL_RED, GL_FLOAT, fluid_amount_[1 - next_]);
    }

    remain_time_ = time_difference;
}<commit_msg>Simple fluid optimization<commit_after>#include "stdafx.h"
#include "FluidSimulation.h"
#include "glext.h"
#include "Parameter.h"
#include <math.h>

extern float interpolatedParameters[];

FluidSimulation::FluidSimulation() {
    next_ = 0;
}

FluidSimulation::~FluidSimulation() {
}

void FluidSimulation::Init(void) {
    next_ = 1;
    for (int y = 0; y < kTotalHeight; y++) {
        for (int x = 0; x < kTotalWidth; x++) {
            fluid_amount_[1 - next_][y][x] = 0.0f;
            fluid_amount_[next_][y][x] = 0.0f;
        }
    }
    remain_time_ = 0.0f;
    current_time = 0.0;

    // Put some fluid to the left and right
#if 1
    last_sum_fluid = 0.0f;
    for (int y = kTotalHeight / 2 - 20; y < kTotalHeight / 2 + 21; y++) {
        for (int x = 0; x < 80; x++) {
            fluid_amount_[1 - next_][y + 20][x] = 1.0f;
            fluid_amount_[1 - next_][y - 20][kTotalWidth - x - 1] = 1.0f;
            last_sum_fluid += 2.0f;
        }
    }
#else
    last_sum_fluid = 0.0f;
    float cell_fluid = FS_TOTAL_SUM_FLUID / (kTotalHeight * kTotalWidth);
    for (int y = 0; y < kTotalHeight; y++) {
        for (int x = 0; x < kTotalHeight; x++) {
            last_sum_fluid += cell_fluid;
            fluid_amount_[1 - next_][y][x] = cell_fluid;
        }
    }
#endif

    glGenTextures(1, &texture_id_);
    glBindTexture(GL_TEXTURE_2D, texture_id_);
    glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
    glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);

    glTexImage2D(GL_TEXTURE_2D, 0, GL_R8,
        kTotalWidth, kTotalHeight,
        0, GL_RED, GL_FLOAT, fluid_amount_[1 - next_]);
}

GLuint FluidSimulation::GetTexture(void) {
    // Send data to GPU
    glBindTexture(GL_TEXTURE_2D, texture_id_);
    return texture_id_;
}

void FluidSimulation::UpdateTime(float time_difference) {
    time_difference += remain_time_;
    remain_time_ = 0.0f;
    bool did_update = false;

    while (time_difference > FS_UPDATE_STEP) {
        current_time += FS_UPDATE_STEP;
        float time = (float)current_time;
        did_update = true;
        int next = next_;
        float add_fluid = FS_TOTAL_SUM_FLUID - last_sum_fluid;
        add_fluid /= kTotalHeight * kTotalWidth;
        last_sum_fluid = 0.0f;
#if 0
        // Reduce speed due to friction
        for (int y = 0; y < kTotalHeight; y++) {
            for (int x = 0; x < kTotalWidth; x++) {
                fluid_velocity_[1 - next][y][x][0] *= FS_VELOCITY_MULTIPLIER;
                if (fabsf(fluid_velocity_[1 - next][y][x][0]) < 1.e-5f) fluid_velocity_[1 - next][y][x][0] = 0.0f;
                fluid_velocity_[1 - next][y][x][1] *= FS_VELOCITY_MULTIPLIER;
                if (fabsf(fluid_velocity_[1 - next][y][x][1]) < 1.e-5f) fluid_velocity_[1 - next][y][x][0] = 0.0f;
            }
        }

        // Do fluid - pull
        for (int y = 1; y < kTotalHeight - 1; y++) {
            for (int x = 1; x < kTotalWidth - 1; x++) {
                float amount = fluid_amount_[1 - next][y][x];
                float pull_amount = amount - amount * amount;
                if (amount > 1.0f) pull_amount = (1.0f - amount) * FS_PUSH_MULTIPLIER;
                if (amount < 0.0f) pull_amount = -amount;  // Should not happen, still negative fluid --> pull
                pull_amount *= FS_PULL_STRENGTH;
                //if (pull_amount > 0.5f) pull_amount = 0.5f;
                fluid_velocity_[1 - next][y][x + 1][0] -= pull_amount;
                fluid_velocity_[1 - next][y][x - 1][0] += pull_amount;
                fluid_velocity_[1 - next][y + 1][x][1] -= pull_amount;
                fluid_velocity_[1 - next][y - 1][x][1] += pull_amount;
            }
        }

        // Apply trace field
        float yp = -1.0f;
        float x_step = 2.0f / kTotalWidth;
        float y_step = 2.0f / kTotalHeight;
        for (int y = 0; y < kTotalHeight; y++) {
            float xp = -1.0f;
            for (int x = 0; x < kTotalWidth; x++) {
                float adjusted_xp = xp;
                float adjusted_yp = yp;

                adjusted_xp += interpolatedParameters[2] * fabsf(yp) * 0.75f;
                adjusted_xp -= interpolatedParameters[3] * fabsf(yp) * 0.75f;
                adjusted_yp += interpolatedParameters[3] * xp * 0.25f;

                float length = sqrtf(adjusted_xp * adjusted_xp + adjusted_yp * adjusted_yp);
                if (length < 0.0001f) length = 0.0001f;
                float x_normal = adjusted_yp / length;
                float y_normal = -adjusted_xp / length;

                // Circle-pos
                float center_move = length - 0.5f;

                fluid_velocity_[1 - next][y][x][0] -= adjusted_xp * center_move * FS_FIELD_STRENGTH_CENTER;
                fluid_velocity_[1 - next][y][x][1] -= adjusted_yp * center_move * FS_FIELD_STRENGTH_CENTER;

                // Rotation
                fluid_velocity_[1 - next][y][x][0] += FS_FIELD_STRENGTH_ROTATION * x_normal * (1.0f - fabsf(center_move));
                fluid_velocity_[1 - next][y][x][1] += FS_FIELD_STRENGTH_ROTATION * y_normal * (1.0f - fabsf(center_move));

                // Move out of middle
                //fluid_velocity_[1 - next][y][x][0] += 0.01f / (length * length + 0.1f);

                xp += x_step;
            }
            yp += y_step;
        }

        // Copy fluid to next frame
        for (int y = 0; y < kTotalHeight; y++) {
            for (int x = 0; x < kTotalWidth; x++) {
                fluid_amount_[next][y][x] = fluid_amount_[1 - next][y][x] + add_fluid;
                last_sum_fluid += fluid_amount_[next][y][x];
                // TODO: Max fluid speed 1.0?
            }
        }
#endif

        // Copy top row that is not copied otherwise
        for (int x = 0; x < kTotalWidth; x++) {
            fluid_amount_[next][0][x] = fluid_amount_[1 - next][0][x];
        }

        // Middle hill precalculation
        float hill_rotation = time * FS_HILL_ROTATION_SPEED;
        float sinf_hill_rotation = sinf(hill_rotation);
        float cosf_hill_rotation = cosf(hill_rotation);
        float sinf_inv_hill_rotation = sinf(-hill_rotation);
        float cosf_inv_hill_rotation = cosf(-hill_rotation);

        // Actually move the fluid
        float yp = -1.0f;
        float x_step = 2.0f / kTotalWidth;
        float y_step = 2.0f / kTotalHeight;
        for (int y = 0; y < kTotalHeight - 1; y++) {
            float xp = -1.0f;

            // Last row just copy
            fluid_amount_[next][y][kTotalWidth - 1] = fluid_amount_[1 - next][y][kTotalWidth - 1];

            for (int x = 0; x < kTotalWidth - 1; x++) {
                float current_amount = fluid_amount_[1 - next][y][x] + add_fluid;
                float right_amount = fluid_amount_[1 - next][y][x + 1];
                float bottom_amount = fluid_amount_[1 - next][y + 1][x];
                float next_amount = fluid_amount_[next][y][x];
                last_sum_fluid += current_amount;

                // Calculate velocities
                float length = sqrtf(xp * xp + yp * yp);
                if (length < 0.0001f) length = 0.0001f;
                float x_normal = yp / length;
                float y_normal = -xp / length;
                // Circle-pos
                float center_move = length - 0.5f;
                float right_velocity = -xp * center_move * FS_FIELD_STRENGTH_CENTER;
                float down_velocity = -yp * center_move * FS_FIELD_STRENGTH_CENTER;
                // Rotation
                right_velocity += FS_FIELD_STRENGTH_ROTATION * x_normal * (1.0f - fabsf(center_move));
                down_velocity += FS_FIELD_STRENGTH_ROTATION * y_normal * (1.0f - fabsf(center_move));

                // Some middle hill
                float hill_rotation = time * FS_HILL_ROTATION_SPEED;
                //float xp_rot = cos(hill_rotation) * xp - sin(hill_rotation) * yp;
                float yp_rot = sinf_hill_rotation * xp + cosf_hill_rotation * yp;
                float line_dist = yp_rot * yp_rot;
                float hill_amount = interpolatedParameters[2] * 0.03f / (line_dist + 0.03f);
                float away_amount = 1.0f * yp_rot * hill_amount;  // goes to linear?
                right_velocity += -sinf_inv_hill_rotation * away_amount;
                down_velocity += cosf_inv_hill_rotation * away_amount;

#if 1
                // Tear up
                right_velocity += 0.3f * sinf(yp * 9.f + time) *
                    cosf(xp * (8.f + sinf(time * 0.3f)) - time * 0.7f) * interpolatedParameters[3];
                down_velocity += 0.3f * cosf(yp * (7.f - cosf(time * 0.27f)) - time * 0.9f) *
                    sinf(xp * 5.f + time * 0.6f) * interpolatedParameters[3];
#endif

#if 1
                float pull_amount = CalculatePull(current_amount);
                float pull_right = CalculatePull(right_amount);
                float pull_bottom = CalculatePull(bottom_amount);
                right_velocity -= pull_amount - pull_right;
                down_velocity -= pull_amount - pull_bottom;
#else
                float pull_amount = CalculatePull(current_amount);
                right_velocity -= pull_amount;
                down_velocity -= pull_amount;
#endif

                if (right_velocity > 0.5f) right_velocity = 0.5f;
                if (down_velocity > 0.5f) down_velocity = 0.5f;

                // move right
                float move_amount;
                if (right_velocity > 0) {
                    move_amount = right_velocity * current_amount;
                } else {
                    move_amount = right_velocity * right_amount;
                }
                next_amount -= move_amount;
                fluid_amount_[next][y][x + 1] += move_amount;
                // Copy y stuff
                float next_bottom = bottom_amount;
                // move bottom
                if (down_velocity > 0) {
                    move_amount = down_velocity * current_amount;
                } else {
                    move_amount = down_velocity * bottom_amount;
                }
                next_amount -= move_amount;
                next_bottom += move_amount;
                fluid_amount_[next][y + 1][x] = next_bottom;

                // Check for invalid numbers. This thing is done last...
                if (isnan(next_amount) || next_amount < -0.5f || next_amount > 1.5f) {
                    next_amount = current_amount;
                }
                if (fabsf(next_amount) < 1e-7f) next_amount = 0.0f;

                fluid_amount_[next][y][x] = next_amount;

                xp += x_step;
            }

            yp += y_step;
        }

        // Check final row:
        for (int x = 0; x < kTotalWidth; x++) {
            int y = kTotalHeight - 1;
            float next_amount = fluid_amount_[next][y][x];
            if (isnan(next_amount) || next_amount < -0.5f || next_amount > 1.5f) {
                fluid_amount_[next][y][x] = fluid_amount_[1 - next][y][x];
            }
        }

        time_difference -= FS_UPDATE_STEP;
        next_ = 1 - next;
        if (time_difference > 0.2f) time_difference = 0.0f;
    }

    if (did_update) {
        glBindTexture(GL_TEXTURE_2D, texture_id_);
        glTexSubImage2D(GL_TEXTURE_2D, 0,
            0, 0, kTotalWidth, kTotalHeight,
            GL_RED, GL_FLOAT, fluid_amount_[1 - next_]);
    }

    remain_time_ = time_difference;
}<|endoftext|>