<commit_before>#ifndef __BH_VE_CPU_BLOCK
#define __BH_VE_CPU_BLOCK
#include <string>
#include <map>

#include "bh.h"
#include "tac.h"
#include "symbol_table.hpp"
#include "utils.hpp"

namespace bohrium{
namespace core{

class Block {
public:
    Block(SymbolTable& globals, std::vector<tac_t>& program);
    ~Block();

    /**
     *  Clear the composed block, does not de-allocate or remove
     *  the associated globals, program and memory allocated for the
     *  block.
     *  It simply clears it for reuse.
     */
    void clear(void);

    /**
     *  Compose the block based based on a subset of program instructions.
     *
     *  @param prg_begin Start of the subset.
     *  @param prg_end End of the subset, to and including prg_end.
     */
    void compose(size_t prg_begin, size_t prg_end);

    /**
     *  Compose the block based based on a subset of program instructions.
     *
     *  TODO: Document
     *
     *  @param prg_begin Start of the subset.
     *  @param prg_end End of the subset, to and including prg_end.
     */
    void compose(bh_ir_kernel& krnl);

    /**
     *  Return the block-local operand-index corresponding
     *  to the given global operand-index.
     *
     *  @param global_idx The global operand-index to resolve
     *  @return The block-local operand-index
     */
    size_t global_to_local(size_t global_idx) const;

    /**
     *  Return the global operand-index corresponding
     *  to the given local operand-index.
     *
     *  @param local_idx The local operand-index to resolve
     *  @return The global operand-index
     */
    size_t local_to_global(size_t local_idx) const;

    /**
     *  Create an operand with block scope based on the operand in global scope.
     *
     *  Reuses operands of equivalent meta-data.
     *
     *  @param global_idx Global index of the operand to add to block scope.
     *
     *  @returns The block-scoped index.
     */
    size_t localize(size_t global_idx);

    /**
     *  Create a symbol for the block.
     *
     *  The textual version of the  symbol looks something like::
     *
     *  symbol_text = ZIP-ADD-2D~1~2~3_~1Cf~2Cf~3Cf
     *
     *  Which will be hashed to some uint32_t value::
     *
     *  symbol = 2111321312412321432424
     *
     *  NOTE: System and extension operations are ignored.
     *        If a block consists of nothing but system and/or extension
     *        opcodes then the symbol will be the empty string "".
     */
    bool symbolize(void);

    //
    // Getters
    //

    /**
     *  Returns the operand with local in block-scope.
     *
     *  @param local_idx Index / name in the block-scope of the operand.
     *  @param A reference to the requested operand.
     */
    operand_t& operand(size_t local_idx);

    /**
     *  Return the array of pointer-operands.
     */
    operand_t** operands(void);

    /**
     * Count of operands in the block.
     */
    size_t noperands(void) const;

    /**
     * Return the tac-instance with the given index.
     */
    tac_t& tac(size_t idx) const;
    tac_t& array_tac(size_t idx) const;

    /**
     *  Count of tacs in the block.
     */
    size_t ntacs(void) const;

    /**
     *  Count of array-tacs in the block.
     */
    size_t narray_tacs(void) const;

    std::string symbol(void) const;
    std::string symbol_text(void) const;

    /**
     *  Returns the iteration space of the block.
     */
    iterspace_t& iterspace(void);

    /**
     *  Update the iteration space of the block.
     *
     *  This means determing the "dominating" LAYOUT, ndim, shape,
     *  and number of elements of an operation within the block.
     *
     *  That is choosing the "worst" LAYOUT, highest ndim, and then
     *  choosing the shape of the operand with chose characteristics.
     *
     *  Since this is what will be the upper-bounds used in when
     *  generating / specializing code, primarily for fusion / contraction.
     *
     *  NOTE: This should be done after applying array contraction or
     *  any other changes to tacs and operands.
     */
    void update_iterspace(void);

    /**
     * Returns a textual representation of the block in dot-format.
     */
    std::string dot(void) const;

    /**
     * Returns a plaintext representation of the block.
     */
    std::string text(void);

    uint32_t omask(void);

private:

    Block();

    SymbolTable& globals_;          // A reference to the global symbol table
    std::vector<tac_t>& program_;   // A reference to the entire bytecode program

    iterspace_t iterspace_;           // The iteration-space of the block

    std::vector<tac_t*> tacs_;      // A subset of the tac-program reprensting the block.
    std::vector<tac_t*> array_tacs_;// A subset of the tac-program containing only array ops.

    //SymbolTable locals_;             // A symbol table with block-scope
    operand_t** operands_;
    size_t noperands_;
    std::map<size_t, size_t> global_to_local_;  // Mapping from global to block-local scope.
    std::map<size_t, size_t> local_to_global_;  // Mapping from global to block-local scope.

    std::string symbol_text_;       // Textual representation of the block
    std::string symbol_;            // Hash of textual representation

    uint32_t omask;

    static const char TAG[];
};

}}
#endif
<commit_msg>cpu: Fix (omask->omask_) name of omask var.<commit_after>#ifndef __BH_VE_CPU_BLOCK
#define __BH_VE_CPU_BLOCK
#include <string>
#include <map>

#include "bh.h"
#include "tac.h"
#include "symbol_table.hpp"
#include "utils.hpp"

namespace bohrium{
namespace core{

class Block {
public:
    Block(SymbolTable& globals, std::vector<tac_t>& program);
    ~Block();

    /**
     *  Clear the composed block, does not de-allocate or remove
     *  the associated globals, program and memory allocated for the
     *  block.
     *  It simply clears it for reuse.
     */
    void clear(void);

    /**
     *  Compose the block based based on a subset of program instructions.
     *
     *  @param prg_begin Start of the subset.
     *  @param prg_end End of the subset, to and including prg_end.
     */
    void compose(size_t prg_begin, size_t prg_end);

    /**
     *  Compose the block based based on a subset of program instructions.
     *
     *  TODO: Document
     *
     *  @param prg_begin Start of the subset.
     *  @param prg_end End of the subset, to and including prg_end.
     */
    void compose(bh_ir_kernel& krnl);

    /**
     *  Return the block-local operand-index corresponding
     *  to the given global operand-index.
     *
     *  @param global_idx The global operand-index to resolve
     *  @return The block-local operand-index
     */
    size_t global_to_local(size_t global_idx) const;

    /**
     *  Return the global operand-index corresponding
     *  to the given local operand-index.
     *
     *  @param local_idx The local operand-index to resolve
     *  @return The global operand-index
     */
    size_t local_to_global(size_t local_idx) const;

    /**
     *  Create an operand with block scope based on the operand in global scope.
     *
     *  Reuses operands of equivalent meta-data.
     *
     *  @param global_idx Global index of the operand to add to block scope.
     *
     *  @returns The block-scoped index.
     */
    size_t localize(size_t global_idx);

    /**
     *  Create a symbol for the block.
     *
     *  The textual version of the  symbol looks something like::
     *
     *  symbol_text = ZIP-ADD-2D~1~2~3_~1Cf~2Cf~3Cf
     *
     *  Which will be hashed to some uint32_t value::
     *
     *  symbol = 2111321312412321432424
     *
     *  NOTE: System and extension operations are ignored.
     *        If a block consists of nothing but system and/or extension
     *        opcodes then the symbol will be the empty string "".
     */
    bool symbolize(void);

    //
    // Getters
    //

    /**
     *  Returns the operand with local in block-scope.
     *
     *  @param local_idx Index / name in the block-scope of the operand.
     *  @param A reference to the requested operand.
     */
    operand_t& operand(size_t local_idx);

    /**
     *  Return the array of pointer-operands.
     */
    operand_t** operands(void);

    /**
     * Count of operands in the block.
     */
    size_t noperands(void) const;

    /**
     * Return the tac-instance with the given index.
     */
    tac_t& tac(size_t idx) const;
    tac_t& array_tac(size_t idx) const;

    /**
     *  Count of tacs in the block.
     */
    size_t ntacs(void) const;

    /**
     *  Count of array-tacs in the block.
     */
    size_t narray_tacs(void) const;

    std::string symbol(void) const;
    std::string symbol_text(void) const;

    /**
     *  Returns the iteration space of the block.
     */
    iterspace_t& iterspace(void);

    /**
     *  Update the iteration space of the block.
     *
     *  This means determing the "dominating" LAYOUT, ndim, shape,
     *  and number of elements of an operation within the block.
     *
     *  That is choosing the "worst" LAYOUT, highest ndim, and then
     *  choosing the shape of the operand with chose characteristics.
     *
     *  Since this is what will be the upper-bounds used in when
     *  generating / specializing code, primarily for fusion / contraction.
     *
     *  NOTE: This should be done after applying array contraction or
     *  any other changes to tacs and operands.
     */
    void update_iterspace(void);

    /**
     * Returns a textual representation of the block in dot-format.
     */
    std::string dot(void) const;

    /**
     * Returns a plaintext representation of the block.
     */
    std::string text(void);

    uint32_t omask(void);

private:

    Block();

    SymbolTable& globals_;          // A reference to the global symbol table
    std::vector<tac_t>& program_;   // A reference to the entire bytecode program

    iterspace_t iterspace_;           // The iteration-space of the block

    std::vector<tac_t*> tacs_;      // A subset of the tac-program reprensting the block.
    std::vector<tac_t*> array_tacs_;// A subset of the tac-program containing only array ops.

    //SymbolTable locals_;             // A symbol table with block-scope
    operand_t** operands_;
    size_t noperands_;
    std::map<size_t, size_t> global_to_local_;  // Mapping from global to block-local scope.
    std::map<size_t, size_t> local_to_global_;  // Mapping from global to block-local scope.

    std::string symbol_text_;       // Textual representation of the block
    std::string symbol_;            // Hash of textual representation

    uint32_t omask_;

    static const char TAG[];
};

}}
#endif
<|endoftext|>


<commit_before>//
//
// Copyright (C) 2005 SIPfoundry Inc.
// Licensed by SIPfoundry under the LGPL license.
//
// Copyright (C) 2005 Pingtel Corp.
// Licensed to SIPfoundry under a Contributor Agreement.
//
// $$
//////////////////////////////////////////////////////////////////////////////

// SYSTEM INCLUDES
#include <string.h>
#include <sys/types.h>
#include <sys/types.h>
#include <regex.h>

// APPLICATION INCLUDES
#include "os/OsSysLog.h"
#include "os/OsDefs.h"
#include "SipRedirectorISN.h"
#include "net/SipSrvLookup.h"
#include "net/Url.h"

#if defined(_WIN32)
#       include "resparse/wnt/sysdep.h"
#       include <resparse/wnt/netinet/in.h>
#       include <resparse/wnt/arpa/nameser.h>
#       include <resparse/wnt/resolv/resolv.h>
#       include <winsock.h>
extern "C" {
#       include "resparse/wnt/inet_aton.h"
}
#elif defined(_VXWORKS)
#       include <stdio.h>
#       include <netdb.h>
#       include <netinet/in.h>
#       include <vxWorks.h>
/* Use local lnameser.h for info missing from VxWorks version --GAT */
/* lnameser.h is a subset of resparse/wnt/arpa/nameser.h                */
#       include <resolv/nameser.h>
#       include <resparse/vxw/arpa/lnameser.h>
/* Use local lresolv.h for info missing from VxWorks version --GAT */
/* lresolv.h is a subset of resparse/wnt/resolv/resolv.h               */
#       include <resolv/resolv.h>
#       include <resparse/vxw/resolv/lresolv.h>
/* #include <sys/socket.h> used sockLib.h instead --GAT */
#       include <sockLib.h>
#       include <resolvLib.h>
#       include <resparse/vxw/hd_string.h>
#elif defined(__pingtel_on_posix__)
#       include <arpa/inet.h>
#       include <netinet/in.h>
#       include <sys/socket.h>
#       include <resolv.h>
#       include <netdb.h>
#else
#       error Unsupported target platform.
#endif

#ifndef __pingtel_on_posix__
extern struct __res_state _sip_res;
#endif

#include "resparse/rr.h"

// The space allocated for returns from res_query.
#define DNS_RESPONSE_SIZE 4096

// DEFINES
// MACROS
// EXTERNAL FUNCTIONS
// EXTERNAL VARIABLES
// CONSTANTS
// STRUCTS
// TYPEDEFS
// FORWARD DECLARATIONS

// Static factory function.
extern "C" RedirectPlugin* getRedirectPlugin(const UtlString& instanceName)
{
   return new SipRedirectorISN(instanceName);
}

// Constructor
SipRedirectorISN::SipRedirectorISN(const UtlString& instanceName) :
   RedirectPlugin(instanceName)
{
}

// Destructor
SipRedirectorISN::~SipRedirectorISN()
{
}

// Read config information.
void SipRedirectorISN::readConfig(OsConfigDb& configDb)
{
   if (configDb.get("BASE_DOMAIN", mBaseDomain) != OS_SUCCESS ||
       mBaseDomain.isNull())
   {
      OsSysLog::add(FAC_SIP, PRI_CRIT,
                    "SipRedirectorISN::readConfig "
                    "BASE_DOMAIN parameter missing or empty");
   }
   else
   {
      OsSysLog::add(FAC_SIP, PRI_INFO,
                    "SipRedirectorISN::readConfig "
                    "BASE_DOMAIN is '%s'", mBaseDomain.data());
   }

   if (configDb.get("PREFIX", mPrefix) != OS_SUCCESS ||
       mPrefix.isNull())
   {
      OsSysLog::add(FAC_SIP, PRI_INFO,
                    "SipRedirectorISN::readConfig "
                    "dialing prefix is empty");
   }
   else
   {
      OsSysLog::add(FAC_SIP, PRI_INFO,
                    "SipRedirectorISN::readConfig "
                    "dialing prefix is '%s'", mPrefix.data());
   }
}

// Initializer
OsStatus
SipRedirectorISN::initialize(OsConfigDb& configDb,
                             SipUserAgent* pSipUserAgent,
                             int redirectorNo,
                             const UtlString& localDomainHost)
{
   return mBaseDomain.isNull() ? OS_FAILED : OS_SUCCESS;
}

// Finalizer
void
SipRedirectorISN::finalize()
{
}

RedirectPlugin::LookUpStatus
SipRedirectorISN::lookUp(
   const SipMessage& message,
   const UtlString& requestString,
   const Url& requestUri,
   const UtlString& method,
   SipMessage& response,
   RequestSeqNo requestSeqNo,
   int redirectorNo,
   SipRedirectorPrivateStorage*& privateStorage)
{
   bool status = false;

   // Get the user part.
   UtlString userId;
   requestUri.getUserId(userId);

   // Test if the user part is in the right format -- prefix followed by digits*digits
   const char* user = userId.data();
   int prefix_length = mPrefix.length();
   // Compare the prefix.
   int i;                       // Length of the extension part.
   if (strncmp(user, mPrefix.data(), prefix_length) == 0)
   {
      // Effectively delete the prefix from the user part.
      user += prefix_length;
      // Check the syntax of the remainder of the user.
      i = strspn(user, "0123456789");
      int j = 0;
      if (i > 0)
      {
         if (user[i] == '*')
         {
            j = strspn(user + i + 1, "0123456789");
            if (user[i + 1 + j] == '\0')
            {
               status = true;
            }
         }
      }
   }

   if (status)
   {
      // Format of user part is correct.  Look for NAPTR records.

      // Create the domain to look up.
      char domain[2 * strlen(user) + mBaseDomain.length()];
      {
         char* p = &domain[0];
         // Copy the extension, reversing it and following each digit with a period.
         for (int k = i; --k >= 0; )
         {
            *p++ = user[k];
            *p++ = '.';
         }
         // Append the ITAD and a period.
         strcpy(p, user + i + 1);
         strcat(p, ".");
         // Append the ITAD root domain.
         strcpy(p, mBaseDomain.data());
      }
      OsSysLog::add(FAC_SIP, PRI_DEBUG,
                    "SipRedirectorISN::lookUp user '%s' has ISN format, domain is '%s'",
                    user, domain);

      // To hold the return of res_query_and_parse.
      res_response* dns_response;
      const char* canonical_name;

      // Make the query and parse the response.
      SipSrvLookup::res_query_and_parse(domain, T_NAPTR, NULL, canonical_name, dns_response);

      if (dns_response != NULL)
      {
         // Search the list of RRs for the 'best' answer.
         // Initialize to values at least 2**16.
         int lowest_order_seen = 1 << 16, lowest_preference_seen = 1 << 16;
         int best_response = -1; // No response found..
         // Search the answer list.
         for (unsigned int i = 0; i < dns_response->header.ancount; i++)
         {
            if (dns_response->answer[i]->rclass == C_IN &&
                dns_response->answer[i]->type == T_NAPTR &&
                // Note we look for the canonical name now.
                strcasecmp(canonical_name, dns_response->answer[i]->name) == 0)
            {
               // A NAPTR record has been found.
               OsSysLog::add(FAC_SIP, PRI_DEBUG,
                             "SipRedirectorISN::LookUp "
                             "NAPTR record found '%s' %d %d %d %d '%s' '%s' '%s' '%s'",
                             dns_response->answer[i]->name,
                             dns_response->answer[i]->rclass,
                             dns_response->answer[i]->type,
                             dns_response->answer[i]->rdata.naptr.order,
                             dns_response->answer[i]->rdata.naptr.preference,
                             dns_response->answer[i]->rdata.naptr.flags,
                             dns_response->answer[i]->rdata.naptr.services,
                             dns_response->answer[i]->rdata.naptr.regexp,
                             dns_response->answer[i]->rdata.naptr.replacement);
               // Accept the record if flags are 'u' and services are 'E2U+sip'.
               // Note that the value 'E2U+sip' is defined by RFC 3764
               // (SIP enumservice) not RFC 2915 (the original NAPTR RFC).
               if (strcasecmp(dns_response->answer[i]->rdata.naptr.flags, "u") == 0 &&
                   strcasecmp(dns_response->answer[i]->rdata.naptr.services, "E2U+sip") == 0)
               {
                  // Check that it has the lowest order and preference values seen so far.
                  if (dns_response->answer[i]->rdata.naptr.order < lowest_order_seen ||
                      (dns_response->answer[i]->rdata.naptr.order == lowest_order_seen &&
                       dns_response->answer[i]->rdata.naptr.preference < lowest_preference_seen))
                  {
                     best_response = i;
                     lowest_order_seen = dns_response->answer[i]->rdata.naptr.order;
                     lowest_preference_seen = dns_response->answer[i]->rdata.naptr.preference;
                  }
               }
            }
         }

         // At this point, best_response (if any) is the response we chose.
         if (best_response != -1)
         {
            char* p = dns_response->answer[best_response]->rdata.naptr.regexp;
            OsSysLog::add(FAC_SIP, PRI_DEBUG,
                          "SipRedirectorISN::LookUp Using NAPTR rewrite '%s' for '%s'",
                          p, domain);
            // Enough space for the 'match' part of the regexp field.
            char match[strlen(p) + 1];
            // Pointer to the 'replace' part of the regexp field.
            char delim;
            const char* replace;
            int i_flag;
            if (res_naptr_split_regexp(p, &delim, match, &replace, &i_flag))
            {
               OsSysLog::add(FAC_SIP, PRI_DEBUG,
                             "SipRedirectorISN::LookUp match = '%s', replace = '%s', i_flag = %d",
                             match, replace, i_flag);
               // Split operation was successful.  Try to match.
               regex_t reg;
               int ret = regcomp(&reg, match, REG_EXTENDED | (i_flag ? REG_ICASE : 0));
               if (ret == 0)
               {
                  // NAPTR matches can have only 9 substitutions.
                  regmatch_t pmatch[9];
                  // regexec returns 0 for success.
                  // Though RFC 3761 and the ISN Cookbook don't say, it appears
                  // that the regexp is matched against the user-part of the SIP URI.
                  if (regexec(&reg, user, 9, pmatch, 0) == 0)
                  {
                     // Match was successful.  Construct the replacement string.
                     // Current usage is that the replacement string is the resulting URI,
                     // not the replacement into the original application-string.
                     char* result = res_naptr_replace(replace, delim, pmatch, user, 0);
                     OsSysLog::add(FAC_SIP, PRI_DEBUG,
                                   "SipRedirectorISN::LookUp result = '%s'",
                                   result);
                     // Note that the replacement string is not
                     // substituted back into the original string, but used
                     // alone as the destination URI.
                     // Parse result string into URI.
                     Url contact(result, TRUE);
                     // Almost all strings are parsable as SIP URIs with a sufficient
                     // number of components missing.  Be we can check that a scheme
                     // was identified, and that a host name was found.
                     // (A string with sufficiently few punctuation characters appears to
                     // be a sip: URI with the scheme missing and only a host name, but
                     // the legal character set for host names is fairly narrow.)
                     UtlString h;
                     contact.getHostAddress(h);
                     if (contact.getScheme() != Url::UnknownUrlScheme && !h.isNull())
                     {
                        RedirectPlugin::addContact(response, requestString,
                                                   contact, "ISN");

                     }
                     else
                     {
                        OsSysLog::add(FAC_SIP, PRI_ERR,
                                      "SipRedirectorISN::LookUp Bad result string '%s' - "
                                      "could not identify URI scheme and/or host name is null - "
                                      "for ISN translation of '%s'",
                                      result, requestString.data());
                     }
                     // Free the result string.
                     free(result);
                  }
                  else
                  {
                     OsSysLog::add(FAC_SIP, PRI_WARNING,
                                   "SipRedirectorISN::LookUp NAPTR regexp '%s' does not match "
                                   "for ISN translation of '%s' - no contact generated",
                                   match, requestString.data());
                  }
                  // Free the parsed regexp structure.
                  regfree(&reg);
               }
               else
               {
                  OsSysLog::add(FAC_SIP, PRI_WARNING,
                                "SipRedirectorISN::LookUp NAPTR regexp '%s' is syntactially invalid "
                                   "for ISN translation of '%s'",
                                match, requestString.data());
               }
            }
            else
            {
               OsSysLog::add(FAC_SIP, PRI_ERR,
                             "SipRedirectorISN::LookUp cannot parse NAPTR regexp field '%s' "
                             "for ISN translation of '%s'",
                             p, requestString.data());
            }
         }
         else
         {
            OsSysLog::add(FAC_SIP, PRI_WARNING,
                          "SipRedirectorISN::LookUp No usable NAPTR found for '%s'"
                          "for ISN translation of '%s'",
                          domain, requestString.data());
         }
      }
      else
      {
         OsSysLog::add(FAC_SIP, PRI_WARNING,
                       "SipRedirectorISN::LookUp no NAPTR record found for domain '%s' "
                       "for ISN translation of '%s'",
                       domain, requestString.data());
      }

      // Free the result of res_parse if necessary.
      if (dns_response != NULL)
      {
         res_free(dns_response);
      }
      if (canonical_name != NULL && canonical_name != domain)
      {
         free((void*) canonical_name);
      }
   }

   return RedirectPlugin::LOOKUP_SUCCESS;
}
<commit_msg>Correct how the ITAD is applied to the NAPTR domain name when processing ISN numbers.<commit_after>//
//
// Copyright (C) 2005 SIPfoundry Inc.
// Licensed by SIPfoundry under the LGPL license.
//
// Copyright (C) 2005 Pingtel Corp.
// Licensed to SIPfoundry under a Contributor Agreement.
//
// $$
//////////////////////////////////////////////////////////////////////////////

// SYSTEM INCLUDES
#include <string.h>
#include <sys/types.h>
#include <sys/types.h>
#include <regex.h>

// APPLICATION INCLUDES
#include "os/OsSysLog.h"
#include "os/OsDefs.h"
#include "SipRedirectorISN.h"
#include "net/SipSrvLookup.h"
#include "net/Url.h"

#if defined(_WIN32)
#       include "resparse/wnt/sysdep.h"
#       include <resparse/wnt/netinet/in.h>
#       include <resparse/wnt/arpa/nameser.h>
#       include <resparse/wnt/resolv/resolv.h>
#       include <winsock.h>
extern "C" {
#       include "resparse/wnt/inet_aton.h"
}
#elif defined(_VXWORKS)
#       include <stdio.h>
#       include <netdb.h>
#       include <netinet/in.h>
#       include <vxWorks.h>
/* Use local lnameser.h for info missing from VxWorks version --GAT */
/* lnameser.h is a subset of resparse/wnt/arpa/nameser.h                */
#       include <resolv/nameser.h>
#       include <resparse/vxw/arpa/lnameser.h>
/* Use local lresolv.h for info missing from VxWorks version --GAT */
/* lresolv.h is a subset of resparse/wnt/resolv/resolv.h               */
#       include <resolv/resolv.h>
#       include <resparse/vxw/resolv/lresolv.h>
/* #include <sys/socket.h> used sockLib.h instead --GAT */
#       include <sockLib.h>
#       include <resolvLib.h>
#       include <resparse/vxw/hd_string.h>
#elif defined(__pingtel_on_posix__)
#       include <arpa/inet.h>
#       include <netinet/in.h>
#       include <sys/socket.h>
#       include <resolv.h>
#       include <netdb.h>
#else
#       error Unsupported target platform.
#endif

#ifndef __pingtel_on_posix__
extern struct __res_state _sip_res;
#endif

#include "resparse/rr.h"

// The space allocated for returns from res_query.
#define DNS_RESPONSE_SIZE 4096

// DEFINES
// MACROS
// EXTERNAL FUNCTIONS
// EXTERNAL VARIABLES
// CONSTANTS
// STRUCTS
// TYPEDEFS
// FORWARD DECLARATIONS

// Static factory function.
extern "C" RedirectPlugin* getRedirectPlugin(const UtlString& instanceName)
{
   return new SipRedirectorISN(instanceName);
}

// Constructor
SipRedirectorISN::SipRedirectorISN(const UtlString& instanceName) :
   RedirectPlugin(instanceName)
{
}

// Destructor
SipRedirectorISN::~SipRedirectorISN()
{
}

// Read config information.
void SipRedirectorISN::readConfig(OsConfigDb& configDb)
{
   if (configDb.get("BASE_DOMAIN", mBaseDomain) != OS_SUCCESS ||
       mBaseDomain.isNull())
   {
      OsSysLog::add(FAC_SIP, PRI_CRIT,
                    "SipRedirectorISN::readConfig "
                    "BASE_DOMAIN parameter missing or empty");
   }
   else
   {
      OsSysLog::add(FAC_SIP, PRI_INFO,
                    "SipRedirectorISN::readConfig "
                    "BASE_DOMAIN is '%s'", mBaseDomain.data());
   }

   if (configDb.get("PREFIX", mPrefix) != OS_SUCCESS ||
       mPrefix.isNull())
   {
      OsSysLog::add(FAC_SIP, PRI_INFO,
                    "SipRedirectorISN::readConfig "
                    "dialing prefix is empty");
   }
   else
   {
      OsSysLog::add(FAC_SIP, PRI_INFO,
                    "SipRedirectorISN::readConfig "
                    "dialing prefix is '%s'", mPrefix.data());
   }
}

// Initializer
OsStatus
SipRedirectorISN::initialize(OsConfigDb& configDb,
                             SipUserAgent* pSipUserAgent,
                             int redirectorNo,
                             const UtlString& localDomainHost)
{
   return mBaseDomain.isNull() ? OS_FAILED : OS_SUCCESS;
}

// Finalizer
void
SipRedirectorISN::finalize()
{
}

RedirectPlugin::LookUpStatus
SipRedirectorISN::lookUp(
   const SipMessage& message,
   const UtlString& requestString,
   const Url& requestUri,
   const UtlString& method,
   SipMessage& response,
   RequestSeqNo requestSeqNo,
   int redirectorNo,
   SipRedirectorPrivateStorage*& privateStorage)
{
   bool status = false;

   // Get the user part.
   UtlString userId;
   requestUri.getUserId(userId);

   // Test if the user part is in the right format -- prefix followed by digits*digits
   const char* user = userId.data();
   int prefix_length = mPrefix.length();
   // Compare the prefix.
   int i;                       // Length of the extension part.
   if (strncmp(user, mPrefix.data(), prefix_length) == 0)
   {
      // Effectively delete the prefix from the user part.
      user += prefix_length;
      // Check the syntax of the remainder of the user.
      i = strspn(user, "0123456789");
      int j = 0;
      if (i > 0)
      {
         if (user[i] == '*')
         {
            j = strspn(user + i + 1, "0123456789");
            if (user[i + 1 + j] == '\0')
            {
               status = true;
            }
         }
      }
   }

   if (status)
   {
      // Format of user part is correct.  Look for NAPTR records.

      // Create the domain to look up.
      char domain[2 * strlen(user) + mBaseDomain.length()];
      {
         char* p = &domain[0];
         // Copy the extension, reversing it and following each digit with a period.
         for (int k = i; --k >= 0; )
         {
            *p++ = user[k];
            *p++ = '.';
         }
         // Append the ITAD and a period.
         strcpy(p, user + i + 1);
         strcat(p, ".");
         // Append the ITAD root domain.
         strcat(p, mBaseDomain.data());
      }
      OsSysLog::add(FAC_SIP, PRI_DEBUG,
                    "SipRedirectorISN::lookUp user '%s' has ISN format, domain is '%s'",
                    user, domain);

      // To hold the return of res_query_and_parse.
      res_response* dns_response;
      const char* canonical_name;

      // Make the query and parse the response.
      SipSrvLookup::res_query_and_parse(domain, T_NAPTR, NULL, canonical_name, dns_response);

      if (dns_response != NULL)
      {
         // Search the list of RRs for the 'best' answer.
         // Initialize to values at least 2**16.
         int lowest_order_seen = 1 << 16, lowest_preference_seen = 1 << 16;
         int best_response = -1; // No response found..
         // Search the answer list.
         for (unsigned int i = 0; i < dns_response->header.ancount; i++)
         {
            if (dns_response->answer[i]->rclass == C_IN &&
                dns_response->answer[i]->type == T_NAPTR &&
                // Note we look for the canonical name now.
                strcasecmp(canonical_name, dns_response->answer[i]->name) == 0)
            {
               // A NAPTR record has been found.
               OsSysLog::add(FAC_SIP, PRI_DEBUG,
                             "SipRedirectorISN::LookUp "
                             "NAPTR record found '%s' %d %d %d %d '%s' '%s' '%s' '%s'",
                             dns_response->answer[i]->name,
                             dns_response->answer[i]->rclass,
                             dns_response->answer[i]->type,
                             dns_response->answer[i]->rdata.naptr.order,
                             dns_response->answer[i]->rdata.naptr.preference,
                             dns_response->answer[i]->rdata.naptr.flags,
                             dns_response->answer[i]->rdata.naptr.services,
                             dns_response->answer[i]->rdata.naptr.regexp,
                             dns_response->answer[i]->rdata.naptr.replacement);
               // Accept the record if flags are 'u' and services are 'E2U+sip'.
               // Note that the value 'E2U+sip' is defined by RFC 3764
               // (SIP enumservice) not RFC 2915 (the original NAPTR RFC).
               if (strcasecmp(dns_response->answer[i]->rdata.naptr.flags, "u") == 0 &&
                   strcasecmp(dns_response->answer[i]->rdata.naptr.services, "E2U+sip") == 0)
               {
                  // Check that it has the lowest order and preference values seen so far.
                  if (dns_response->answer[i]->rdata.naptr.order < lowest_order_seen ||
                      (dns_response->answer[i]->rdata.naptr.order == lowest_order_seen &&
                       dns_response->answer[i]->rdata.naptr.preference < lowest_preference_seen))
                  {
                     best_response = i;
                     lowest_order_seen = dns_response->answer[i]->rdata.naptr.order;
                     lowest_preference_seen = dns_response->answer[i]->rdata.naptr.preference;
                  }
               }
            }
         }

         // At this point, best_response (if any) is the response we chose.
         if (best_response != -1)
         {
            char* p = dns_response->answer[best_response]->rdata.naptr.regexp;
            OsSysLog::add(FAC_SIP, PRI_DEBUG,
                          "SipRedirectorISN::LookUp Using NAPTR rewrite '%s' for '%s'",
                          p, domain);
            // Enough space for the 'match' part of the regexp field.
            char match[strlen(p) + 1];
            // Pointer to the 'replace' part of the regexp field.
            char delim;
            const char* replace;
            int i_flag;
            if (res_naptr_split_regexp(p, &delim, match, &replace, &i_flag))
            {
               OsSysLog::add(FAC_SIP, PRI_DEBUG,
                             "SipRedirectorISN::LookUp match = '%s', replace = '%s', i_flag = %d",
                             match, replace, i_flag);
               // Split operation was successful.  Try to match.
               regex_t reg;
               int ret = regcomp(&reg, match, REG_EXTENDED | (i_flag ? REG_ICASE : 0));
               if (ret == 0)
               {
                  // NAPTR matches can have only 9 substitutions.
                  regmatch_t pmatch[9];
                  // regexec returns 0 for success.
                  // Though RFC 3761 and the ISN Cookbook don't say, it appears
                  // that the regexp is matched against the user-part of the SIP URI.
                  if (regexec(&reg, user, 9, pmatch, 0) == 0)
                  {
                     // Match was successful.  Construct the replacement string.
                     // Current usage is that the replacement string is the resulting URI,
                     // not the replacement into the original application-string.
                     char* result = res_naptr_replace(replace, delim, pmatch, user, 0);
                     OsSysLog::add(FAC_SIP, PRI_DEBUG,
                                   "SipRedirectorISN::LookUp result = '%s'",
                                   result);
                     // Note that the replacement string is not
                     // substituted back into the original string, but used
                     // alone as the destination URI.
                     // Parse result string into URI.
                     Url contact(result, TRUE);
                     // Almost all strings are parsable as SIP URIs with a sufficient
                     // number of components missing.  Be we can check that a scheme
                     // was identified, and that a host name was found.
                     // (A string with sufficiently few punctuation characters appears to
                     // be a sip: URI with the scheme missing and only a host name, but
                     // the legal character set for host names is fairly narrow.)
                     UtlString h;
                     contact.getHostAddress(h);
                     if (contact.getScheme() != Url::UnknownUrlScheme && !h.isNull())
                     {
                        RedirectPlugin::addContact(response, requestString,
                                                   contact, "ISN");

                     }
                     else
                     {
                        OsSysLog::add(FAC_SIP, PRI_ERR,
                                      "SipRedirectorISN::LookUp Bad result string '%s' - "
                                      "could not identify URI scheme and/or host name is null - "
                                      "for ISN translation of '%s'",
                                      result, requestString.data());
                     }
                     // Free the result string.
                     free(result);
                  }
                  else
                  {
                     OsSysLog::add(FAC_SIP, PRI_WARNING,
                                   "SipRedirectorISN::LookUp NAPTR regexp '%s' does not match "
                                   "for ISN translation of '%s' - no contact generated",
                                   match, requestString.data());
                  }
                  // Free the parsed regexp structure.
                  regfree(&reg);
               }
               else
               {
                  OsSysLog::add(FAC_SIP, PRI_WARNING,
                                "SipRedirectorISN::LookUp NAPTR regexp '%s' is syntactially invalid "
                                   "for ISN translation of '%s'",
                                match, requestString.data());
               }
            }
            else
            {
               OsSysLog::add(FAC_SIP, PRI_ERR,
                             "SipRedirectorISN::LookUp cannot parse NAPTR regexp field '%s' "
                             "for ISN translation of '%s'",
                             p, requestString.data());
            }
         }
         else
         {
            OsSysLog::add(FAC_SIP, PRI_WARNING,
                          "SipRedirectorISN::LookUp No usable NAPTR found for '%s'"
                          "for ISN translation of '%s'",
                          domain, requestString.data());
         }
      }
      else
      {
         OsSysLog::add(FAC_SIP, PRI_WARNING,
                       "SipRedirectorISN::LookUp no NAPTR record found for domain '%s' "
                       "for ISN translation of '%s'",
                       domain, requestString.data());
      }

      // Free the result of res_parse if necessary.
      if (dns_response != NULL)
      {
         res_free(dns_response);
      }
      if (canonical_name != NULL && canonical_name != domain)
      {
         free((void*) canonical_name);
      }
   }

   return RedirectPlugin::LOOKUP_SUCCESS;
}
<|endoftext|>


<commit_before>///////////////////////////////////////////////////////////////////////////////
//
// File Monodomain.cpp
//
// For more information, please see: http://www.nektar.info
//
// The MIT License
//
// Copyright (c) 2006 Division of Applied Mathematics, Brown University (USA),
// Department of Aeronautics, Imperial College London (UK), and Scientific
// Computing and Imaging Institute, University of Utah (USA).
//
// License for the specific language governing rights and limitations under
// 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.
//
// Description: Monodomain cardiac electrophysiology homogenised model.
//
///////////////////////////////////////////////////////////////////////////////

#include <iostream>

#include <CardiacEPSolver/EquationSystems/Monodomain.h>

namespace Nektar
{
    /**
     * @class Monodomain
     *
     * Base model of cardiac electrophysiology of the form
     * \f{align*}{
     *     \frac{\partial u}{\partial t} = \nabla^2 u + J_{ion},
     * \f}
     * where the reaction term, \f$J_{ion}\f$ is defined by a specific cell
     * model.
     *
     * This implementation, at present, treats the reaction terms explicitly
     * and the diffusive element implicitly.
     */

    /**
     * Registers the class with the Factory.
     */
    string Monodomain::className
            = GetEquationSystemFactory().RegisterCreatorFunction(
                "Monodomain",
                Monodomain::create,
                "Monodomain model of cardiac electrophysiology.");

    /**
     *
     */
    Monodomain::Monodomain(
            const LibUtilities::SessionReaderSharedPtr& pSession)
        : UnsteadySystem(pSession)
    {
    }

    void Monodomain::v_InitObject()
    {
        UnsteadySystem::v_InitObject();

        m_session->LoadParameter("Chi",        m_chi);
        m_session->LoadParameter("Cm",         m_capMembrane);

        std::string vCellModel;
        m_session->LoadSolverInfo("CELLMODEL", vCellModel, "");

        ASSERTL0(vCellModel != "", "Cell Model not specified.");

        m_cell = GetCellModelFactory().CreateInstance(vCellModel, m_session, m_fields[0]);

        m_intVariables.push_back(0);

        // Load variable coefficients
        StdRegions::VarCoeffType varCoeffEnum[3] = {
                StdRegions::eVarCoeffD00,
                StdRegions::eVarCoeffD11,
                StdRegions::eVarCoeffD22
        };
        std::string varName = "intensity";
        std::string varCoeffs[3] = {
                "AnisotropicConductivityX",
                "AnisotropicConductivityY",
                "AnisotropicConductivityZ"
        };

        Array<OneD, NekDouble> vTemp;
        if (m_session->DefinesFunction("IsotropicConductivity"))
        {
            EvaluateFunction(varName, vTemp, "IsotropicConductivity");
            for (int i = 0; i < m_spacedim; ++i)
            {
                m_vardiff[varCoeffEnum[i]] = vTemp;
            }
        }
        else if (m_session->DefinesFunction(varCoeffs[0]))
        {
            for (int i = 0; i < m_spacedim; ++i)
            {
                ASSERTL0(m_session->DefinesFunction(varCoeffs[i], varName),
                    "Function '" + varCoeffs[i] + "' not correctly defined.");
                EvaluateFunction(varName, vTemp, varCoeffs[i]);
                m_vardiff[varCoeffEnum[i]] = vTemp;
            }
        }

        for (int i = 0; i < m_spacedim; ++i)
        {
            if (m_session->DefinesParameter("d_min"))
            {
                // Normalise and invert
                int nq = m_fields[0]->GetNpoints();
                NekDouble f_min = m_session->GetParameter("d_min");
                NekDouble f_max = m_session->GetParameter("d_max");
                NekDouble f_range = f_max - f_min;
                NekDouble o_min = m_session->GetParameter("o_min");
                NekDouble o_max = m_session->GetParameter("o_max");
                Vmath::Sadd(nq, -f_min, m_vardiff[varCoeffEnum[i]], 1, m_vardiff[varCoeffEnum[i]], 1);
                for (int j = 0; j < nq; ++j)
                {
                    if (m_vardiff[varCoeffEnum[i]][j] < 0)
                    {
                        m_vardiff[varCoeffEnum[i]][j] = 0.0;
                    }
                    if (m_vardiff[varCoeffEnum[i]][j] > f_range)
                    {
                        m_vardiff[varCoeffEnum[i]][j] = f_range;
                    }
                }
                Vmath::Smul(nq, -1.0/f_range, m_vardiff[varCoeffEnum[i]], 1, m_vardiff[varCoeffEnum[i]], 1);
                Vmath::Sadd(nq, 1.0, m_vardiff[varCoeffEnum[i]], 1, m_vardiff[varCoeffEnum[i]], 1);
                Vmath::Smul(nq, o_max-o_min, m_vardiff[varCoeffEnum[i]], 1, m_vardiff[varCoeffEnum[i]], 1);
                Vmath::Sadd(nq, o_min, m_vardiff[varCoeffEnum[i]], 1, m_vardiff[varCoeffEnum[i]], 1);
            }

            m_fields[0]->FwdTrans_IterPerExp(m_vardiff[varCoeffEnum[i]],
                                             m_fields[0]->UpdateCoeffs());
            std::stringstream filename;
            filename << varCoeffs[i];
            if (m_comm->GetSize() > 1)
            {
                filename << "_P" << m_comm->GetRank();
            }
            filename << ".fld";
            WriteFld(filename.str());

        }

        if (m_session->DefinesParameter("StimulusDuration"))
        {
            ASSERTL0(m_session->DefinesFunction("Stimulus", "u"),
                    "Stimulus function not defined.");
            m_session->LoadParameter("StimulusDuration", m_stimDuration);
        }
        else
        {
            m_stimDuration = 0;
        }

        if (!m_explicitDiffusion)
        {
            m_ode.DefineImplicitSolve (&Monodomain::DoImplicitSolve, this);
        }
        m_ode.DefineOdeRhs(&Monodomain::DoOdeRhs, this);
    }

    /**
     *
     */
    Monodomain::~Monodomain()
    {

    }

    /**
     * @param   inarray         Input array.
     * @param   outarray        Output array.
     * @param   time            Current simulation time.
     * @param   lambda          Timestep.
     */
    void Monodomain::DoImplicitSolve(
            const Array<OneD, const Array<OneD, NekDouble> >&inarray,
                  Array<OneD, Array<OneD, NekDouble> >&outarray,
            const NekDouble time,
            const NekDouble lambda)
    {
        int nvariables  = inarray.num_elements();
        int ncoeffs     = inarray[0].num_elements();
        int nq          = m_fields[0]->GetNpoints();
        StdRegions::ConstFactorMap factors;
        // lambda = \Delta t
        factors[StdRegions::eFactorLambda] = 1.0/lambda*m_chi*m_capMembrane;

        // We solve ( \nabla^2 - HHlambda ) Y[i] = rhs [i]
        // inarray = input: \hat{rhs} -> output: \hat{Y}
        // outarray = output: nabla^2 \hat{Y}
        // where \hat = modal coeffs
        for (int i = 0; i < nvariables; ++i)
        {
            // Multiply 1.0/timestep
            Vmath::Smul(nq, -factors[StdRegions::eFactorLambda], inarray[i], 1,
                                            m_fields[i]->UpdatePhys(), 1);

            // Solve a system of equations with Helmholtz solver and transform
            // back into physical space.
            m_fields[i]->HelmSolve(m_fields[i]->GetPhys(),
                                   m_fields[i]->UpdateCoeffs(), NullFlagList,
                                   factors, m_vardiff);

            m_fields[i]->BwdTrans( m_fields[i]->GetCoeffs(),
                                   m_fields[i]->UpdatePhys());
            m_fields[i]->SetPhysState(true);

            // Copy the solution vector (required as m_fields must be set).
            outarray[i] = m_fields[i]->GetPhys();
        }
    }

    void Monodomain::DoOdeRhs(
            const Array<OneD, const  Array<OneD, NekDouble> >&inarray,
                  Array<OneD,        Array<OneD, NekDouble> >&outarray,
            const NekDouble time)
    {
        int nq = m_fields[0]->GetNpoints();
        int nvar = inarray.num_elements();

        m_cell->TimeIntegrate(inarray, outarray, time);

        if (m_stimDuration > 0 && time < m_stimDuration)
        {
            Array<OneD,NekDouble> x0(nq);
            Array<OneD,NekDouble> x1(nq);
            Array<OneD,NekDouble> x2(nq);
            Array<OneD,NekDouble> result(nq);

            // get the coordinates
            m_fields[0]->GetCoords(x0,x1,x2);

            LibUtilities::EquationSharedPtr ifunc
                    = m_session->GetFunction("Stimulus", "u");
            ifunc->Evaluate(x0,x1,x2,time, result);

            Vmath::Vadd(nq, outarray[0], 1, result, 1, outarray[0], 1);
        }
        Vmath::Smul(nq, 1.0/m_capMembrane, outarray[0], 1, outarray[0], 1);
    }

    void Monodomain::v_SetInitialConditions(NekDouble initialtime,
                        bool dumpInitialConditions)
    {
        EquationSystem::v_SetInitialConditions(initialtime, dumpInitialConditions);
        m_cell->Initialise();
    }

    /**
     *
     */
    void Monodomain::v_PrintSummary(std::ostream &out)
    {
        UnsteadySystem::v_PrintSummary(out);
        if (m_session->DefinesFunction("d00") &&
            m_session->GetFunctionType("d00", "intensity") == LibUtilities::eFunctionTypeExpression)
        {
            out << "\tDiffusivity-x   : "
                << m_session->GetFunction("d00", "intensity")->GetExpression()
                << endl;
        }
        if (m_session->DefinesFunction("d11") &&
            m_session->GetFunctionType("d11", "intensity") == LibUtilities::eFunctionTypeExpression)
        {
            out << "\tDiffusivity-x   : "
                << m_session->GetFunction("d11", "intensity")->GetExpression()
                << endl;
        }
        if (m_session->DefinesFunction("d22") &&
            m_session->GetFunctionType("d22", "intensity") == LibUtilities::eFunctionTypeExpression)
        {
            out << "\tDiffusivity-x   : "
                << m_session->GetFunction("d22", "intensity")->GetExpression()
                << endl;
        }
        m_cell->PrintSummary(out);
    }

}
<commit_msg>Added missing check when setting up variable coefficients.<commit_after>///////////////////////////////////////////////////////////////////////////////
//
// File Monodomain.cpp
//
// For more information, please see: http://www.nektar.info
//
// The MIT License
//
// Copyright (c) 2006 Division of Applied Mathematics, Brown University (USA),
// Department of Aeronautics, Imperial College London (UK), and Scientific
// Computing and Imaging Institute, University of Utah (USA).
//
// License for the specific language governing rights and limitations under
// 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.
//
// Description: Monodomain cardiac electrophysiology homogenised model.
//
///////////////////////////////////////////////////////////////////////////////

#include <iostream>

#include <CardiacEPSolver/EquationSystems/Monodomain.h>

namespace Nektar
{
    /**
     * @class Monodomain
     *
     * Base model of cardiac electrophysiology of the form
     * \f{align*}{
     *     \frac{\partial u}{\partial t} = \nabla^2 u + J_{ion},
     * \f}
     * where the reaction term, \f$J_{ion}\f$ is defined by a specific cell
     * model.
     *
     * This implementation, at present, treats the reaction terms explicitly
     * and the diffusive element implicitly.
     */

    /**
     * Registers the class with the Factory.
     */
    string Monodomain::className
            = GetEquationSystemFactory().RegisterCreatorFunction(
                "Monodomain",
                Monodomain::create,
                "Monodomain model of cardiac electrophysiology.");

    /**
     *
     */
    Monodomain::Monodomain(
            const LibUtilities::SessionReaderSharedPtr& pSession)
        : UnsteadySystem(pSession)
    {
    }

    void Monodomain::v_InitObject()
    {
        UnsteadySystem::v_InitObject();

        m_session->LoadParameter("Chi",        m_chi);
        m_session->LoadParameter("Cm",         m_capMembrane);

        std::string vCellModel;
        m_session->LoadSolverInfo("CELLMODEL", vCellModel, "");

        ASSERTL0(vCellModel != "", "Cell Model not specified.");

        m_cell = GetCellModelFactory().CreateInstance(vCellModel, m_session, m_fields[0]);

        m_intVariables.push_back(0);

        // Load variable coefficients
        StdRegions::VarCoeffType varCoeffEnum[3] = {
                StdRegions::eVarCoeffD00,
                StdRegions::eVarCoeffD11,
                StdRegions::eVarCoeffD22
        };
        std::string varName = "intensity";
        std::string varCoeffs[3] = {
                "AnisotropicConductivityX",
                "AnisotropicConductivityY",
                "AnisotropicConductivityZ"
        };

        Array<OneD, NekDouble> vTemp;
        if (m_session->DefinesFunction("IsotropicConductivity"))
        {
            EvaluateFunction(varName, vTemp, "IsotropicConductivity");
            for (int i = 0; i < m_spacedim; ++i)
            {
                m_vardiff[varCoeffEnum[i]] = vTemp;
            }
        }
        else if (m_session->DefinesFunction(varCoeffs[0]))
        {
            for (int i = 0; i < m_spacedim; ++i)
            {
                ASSERTL0(m_session->DefinesFunction(varCoeffs[i], varName),
                    "Function '" + varCoeffs[i] + "' not correctly defined.");
                EvaluateFunction(varName, vTemp, varCoeffs[i]);
                m_vardiff[varCoeffEnum[i]] = vTemp;
            }
        }

        if (!m_vardiff.empty())
        {
            // Process each of the defined variable coefficients
            for (int i = 0; i < m_spacedim; ++i)
            {
                // If scaling parameters defined, do scaling
                if (m_session->DefinesParameter("d_min"))
                {
                    // Normalise and invert
                    int nq = m_fields[0]->GetNpoints();
                    NekDouble f_min = m_session->GetParameter("d_min");
                    NekDouble f_max = m_session->GetParameter("d_max");
                    NekDouble f_range = f_max - f_min;
                    NekDouble o_min = m_session->GetParameter("o_min");
                    NekDouble o_max = m_session->GetParameter("o_max");
                    Vmath::Sadd(nq, -f_min, m_vardiff[varCoeffEnum[i]], 1, m_vardiff[varCoeffEnum[i]], 1);
                    for (int j = 0; j < nq; ++j)
                    {
                        if (m_vardiff[varCoeffEnum[i]][j] < 0)
                        {
                            m_vardiff[varCoeffEnum[i]][j] = 0.0;
                        }
                        if (m_vardiff[varCoeffEnum[i]][j] > f_range)
                        {
                            m_vardiff[varCoeffEnum[i]][j] = f_range;
                        }
                    }
                    Vmath::Smul(nq, -1.0/f_range, m_vardiff[varCoeffEnum[i]], 1, m_vardiff[varCoeffEnum[i]], 1);
                    Vmath::Sadd(nq, 1.0, m_vardiff[varCoeffEnum[i]], 1, m_vardiff[varCoeffEnum[i]], 1);
                    Vmath::Smul(nq, o_max-o_min, m_vardiff[varCoeffEnum[i]], 1, m_vardiff[varCoeffEnum[i]], 1);
                    Vmath::Sadd(nq, o_min, m_vardiff[varCoeffEnum[i]], 1, m_vardiff[varCoeffEnum[i]], 1);
                }

                // Transform variable coefficient and write out to file.
                m_fields[0]->FwdTrans_IterPerExp(m_vardiff[varCoeffEnum[i]],
                                                 m_fields[0]->UpdateCoeffs());
                std::stringstream filename;
                filename << varCoeffs[i];
                if (m_comm->GetSize() > 1)
                {
                    filename << "_P" << m_comm->GetRank();
                }
                filename << ".fld";
                WriteFld(filename.str());
            }
        }

        if (m_session->DefinesParameter("StimulusDuration"))
        {
            ASSERTL0(m_session->DefinesFunction("Stimulus", "u"),
                    "Stimulus function not defined.");
            m_session->LoadParameter("StimulusDuration", m_stimDuration);
        }
        else
        {
            m_stimDuration = 0;
        }

        if (!m_explicitDiffusion)
        {
            m_ode.DefineImplicitSolve (&Monodomain::DoImplicitSolve, this);
        }
        m_ode.DefineOdeRhs(&Monodomain::DoOdeRhs, this);
    }

    /**
     *
     */
    Monodomain::~Monodomain()
    {

    }

    /**
     * @param   inarray         Input array.
     * @param   outarray        Output array.
     * @param   time            Current simulation time.
     * @param   lambda          Timestep.
     */
    void Monodomain::DoImplicitSolve(
            const Array<OneD, const Array<OneD, NekDouble> >&inarray,
                  Array<OneD, Array<OneD, NekDouble> >&outarray,
            const NekDouble time,
            const NekDouble lambda)
    {
        int nvariables  = inarray.num_elements();
        int ncoeffs     = inarray[0].num_elements();
        int nq          = m_fields[0]->GetNpoints();
        StdRegions::ConstFactorMap factors;
        // lambda = \Delta t
        factors[StdRegions::eFactorLambda] = 1.0/lambda*m_chi*m_capMembrane;

        // We solve ( \nabla^2 - HHlambda ) Y[i] = rhs [i]
        // inarray = input: \hat{rhs} -> output: \hat{Y}
        // outarray = output: nabla^2 \hat{Y}
        // where \hat = modal coeffs
        for (int i = 0; i < nvariables; ++i)
        {
            // Multiply 1.0/timestep
            Vmath::Smul(nq, -factors[StdRegions::eFactorLambda], inarray[i], 1,
                                            m_fields[i]->UpdatePhys(), 1);

            // Solve a system of equations with Helmholtz solver and transform
            // back into physical space.
            m_fields[i]->HelmSolve(m_fields[i]->GetPhys(),
                                   m_fields[i]->UpdateCoeffs(), NullFlagList,
                                   factors, m_vardiff);

            m_fields[i]->BwdTrans( m_fields[i]->GetCoeffs(),
                                   m_fields[i]->UpdatePhys());
            m_fields[i]->SetPhysState(true);

            // Copy the solution vector (required as m_fields must be set).
            outarray[i] = m_fields[i]->GetPhys();
        }
    }

    void Monodomain::DoOdeRhs(
            const Array<OneD, const  Array<OneD, NekDouble> >&inarray,
                  Array<OneD,        Array<OneD, NekDouble> >&outarray,
            const NekDouble time)
    {
        int nq = m_fields[0]->GetNpoints();
        int nvar = inarray.num_elements();

        m_cell->TimeIntegrate(inarray, outarray, time);

        if (m_stimDuration > 0 && time < m_stimDuration)
        {
            Array<OneD,NekDouble> x0(nq);
            Array<OneD,NekDouble> x1(nq);
            Array<OneD,NekDouble> x2(nq);
            Array<OneD,NekDouble> result(nq);

            // get the coordinates
            m_fields[0]->GetCoords(x0,x1,x2);

            LibUtilities::EquationSharedPtr ifunc
                    = m_session->GetFunction("Stimulus", "u");
            ifunc->Evaluate(x0,x1,x2,time, result);

            Vmath::Vadd(nq, outarray[0], 1, result, 1, outarray[0], 1);
        }
        Vmath::Smul(nq, 1.0/m_capMembrane, outarray[0], 1, outarray[0], 1);
    }

    void Monodomain::v_SetInitialConditions(NekDouble initialtime,
                        bool dumpInitialConditions)
    {
        EquationSystem::v_SetInitialConditions(initialtime, dumpInitialConditions);
        m_cell->Initialise();
    }

    /**
     *
     */
    void Monodomain::v_PrintSummary(std::ostream &out)
    {
        UnsteadySystem::v_PrintSummary(out);
        if (m_session->DefinesFunction("d00") &&
            m_session->GetFunctionType("d00", "intensity") == LibUtilities::eFunctionTypeExpression)
        {
            out << "\tDiffusivity-x   : "
                << m_session->GetFunction("d00", "intensity")->GetExpression()
                << endl;
        }
        if (m_session->DefinesFunction("d11") &&
            m_session->GetFunctionType("d11", "intensity") == LibUtilities::eFunctionTypeExpression)
        {
            out << "\tDiffusivity-x   : "
                << m_session->GetFunction("d11", "intensity")->GetExpression()
                << endl;
        }
        if (m_session->DefinesFunction("d22") &&
            m_session->GetFunctionType("d22", "intensity") == LibUtilities::eFunctionTypeExpression)
        {
            out << "\tDiffusivity-x   : "
                << m_session->GetFunction("d22", "intensity")->GetExpression()
                << endl;
        }
        m_cell->PrintSummary(out);
    }

}
<|endoftext|>


<commit_before>///////////////////////////////////////////////////////////////////////////////
//
// File Monodomain.cpp
//
// For more information, please see: http://www.nektar.info
//
// The MIT License
//
// Copyright (c) 2006 Division of Applied Mathematics, Brown University (USA),
// Department of Aeronautics, Imperial College London (UK), and Scientific
// Computing and Imaging Institute, University of Utah (USA).
//
// License for the specific language governing rights and limitations under
// 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.
//
// Description: Monodomain cardiac electrophysiology homogenised model.
//
///////////////////////////////////////////////////////////////////////////////

#include <iostream>

#include <CardiacEPSolver/EquationSystems/Monodomain.h>
#include <CardiacEPSolver/Filters/FilterCheckpointCellModel.h>

namespace Nektar
{
    /**
     * @class Monodomain
     *
     * Base model of cardiac electrophysiology of the form
     * \f{align*}{
     *     \frac{\partial u}{\partial t} = \nabla^2 u + J_{ion},
     * \f}
     * where the reaction term, \f$J_{ion}\f$ is defined by a specific cell
     * model.
     *
     * This implementation, at present, treats the reaction terms explicitly
     * and the diffusive element implicitly.
     */

    /**
     * Registers the class with the Factory.
     */
    string Monodomain::className
            = GetEquationSystemFactory().RegisterCreatorFunction(
                "Monodomain",
                Monodomain::create,
                "Monodomain model of cardiac electrophysiology.");

    /**
     *
     */
    Monodomain::Monodomain(
            const LibUtilities::SessionReaderSharedPtr& pSession)
        : UnsteadySystem(pSession)
    {
    }

    /**
     *
     */
    void Monodomain::v_InitObject()
    {
        UnsteadySystem::v_InitObject();

        m_session->LoadParameter("Chi",        m_chi);
        m_session->LoadParameter("Cm",         m_capMembrane);

        std::string vCellModel;
        m_session->LoadSolverInfo("CELLMODEL", vCellModel, "");

        ASSERTL0(vCellModel != "", "Cell Model not specified.");

        m_cell = GetCellModelFactory().CreateInstance(
                                        vCellModel, m_session, m_fields[0]);

        m_intVariables.push_back(0);

        // Load variable coefficients
        StdRegions::VarCoeffType varCoeffEnum[6] = {
                StdRegions::eVarCoeffD00,
                StdRegions::eVarCoeffD01,
                StdRegions::eVarCoeffD11,
                StdRegions::eVarCoeffD02,
                StdRegions::eVarCoeffD12,
                StdRegions::eVarCoeffD22
        };
        std::string varName = "intensity";
        std::string aniso_var[3] = {
                "fx", "fy", "fz"
        };
        int nq = m_fields[0]->GetNpoints();
        Array<OneD, NekDouble> vTemp;
        Array<OneD, NekDouble> vTemp_i;
        Array<OneD, NekDouble> vTemp_j;

        // Allocate storage for variable coeffs and initialize to 1.
        for (int i = 0; i < m_spacedim*(m_spacedim+1)/2; ++i)
        {
            m_vardiff[varCoeffEnum[i]] = Array<OneD, NekDouble>(nq, 1.0);
        }

        // Apply fibre map f \in [0,1], scale to conductivity range
        // [o_min,o_max], specified by the session parameters o_min and o_max
        if (m_session->DefinesFunction("AnisotropicConductivity"))
        {
            if (m_session->DefinesCmdLineArgument("verbose"))
            {
                cout << "Loading Anisotropic Fibre map." << endl;
            }

            NekDouble o_min = m_session->GetParameter("o_min");
            NekDouble o_max = m_session->GetParameter("o_max");

            int k = 0;

            /*
             * Diffusivity matrix is upper triangular and defined as
             *    d_00   d_01  d_02
             *           d_11  d_12
             *                 d_22
             *
             * Given a principle fibre direction _f_ the diffusivity is given
             * by
             *    d_ij = { D_2 + (D_1 - D_2) f_i f_j   if i==j
             *           {       (D_1 - D_2) f_i f_j   if i!=j
             *
             * The vector _f_ is given in terms of the variables fx,fy,fz in the
             * function AnisotropicConductivity. The values of D_1 and D_2 are
             * the parameters o_max and o_min, respectively.
             */

            // Loop through columns of D
            for (int j = 0; j < m_spacedim; ++j)
            {
                ASSERTL0(m_session->DefinesFunction("AnisotropicConductivity",
                                                    aniso_var[j]),
                         "Function 'AnisotropicConductivity' not correctly "
                         "defined.");
                EvaluateFunction(aniso_var[j], vTemp_j,
                                 "AnisotropicConductivity");

                // Loop through rows of D
                for (int i = 0; i < j + 1; ++i)
                {
                    ASSERTL0(m_session->DefinesFunction("AnisotropicConductivity",
                                                        aniso_var[i]),
                             "Function 'AnisotropicConductivity' not correctly "
                             "defined.");
                    EvaluateFunction(aniso_var[i], vTemp_i,
                                     "AnisotropicConductivity");

                    Vmath::Vmul(nq, vTemp_i, 1, vTemp_j, 1,
                                           m_vardiff[varCoeffEnum[k]], 1);

                    Vmath::Smul(nq, o_max-o_min,
                                           m_vardiff[varCoeffEnum[k]], 1,
                                           m_vardiff[varCoeffEnum[k]], 1);

                    if (i == j)
                    {
                        Vmath::Sadd(nq, o_min, m_vardiff[varCoeffEnum[k]], 1,
                                               m_vardiff[varCoeffEnum[k]], 1);
                    }

                    ++k;
                }
            }
        }

        // Scale by scar map (range 0->1) derived from intensity map
        // (range d_min -> d_max)
        if (m_session->DefinesFunction("IsotropicConductivity"))
        {
            if (m_session->DefinesCmdLineArgument("verbose"))
            {
                cout << "Loading Isotropic Conductivity map." << endl;
            }

            NekDouble f_min = m_session->GetParameter("d_min");
            NekDouble f_max = m_session->GetParameter("d_max");

            EvaluateFunction(varName, vTemp, "IsotropicConductivity");

            // Threshold based on d_min, d_max
            for (int j = 0; j < nq; ++j)
            {
                vTemp[j] = (vTemp[j] < f_min ? f_min : vTemp[j]);
                vTemp[j] = (vTemp[j] > f_max ? f_max : vTemp[j]);
            }

            // Rescale to s \in [0,1] (0 maps to d_max, 1 maps to d_min)
            Vmath::Sadd(nq, -f_min, vTemp, 1, vTemp, 1);
            Vmath::Smul(nq, -1.0/(f_max-f_min), vTemp, 1, vTemp, 1);
            Vmath::Sadd(nq, 1.0, vTemp, 1, vTemp, 1);

            // Scale anisotropic conductivity values
            for (int i = 0; i < m_spacedim; ++i)
            {
                Vmath::Vmul(nq, vTemp, 1,
                                m_vardiff[varCoeffEnum[i]], 1,
                                m_vardiff[varCoeffEnum[i]], 1);
            }
        }

        // Write out conductivity values
        for (int i = 0; i < m_spacedim; ++i)
        {
            // Transform variable coefficient and write out to file.
            m_fields[0]->FwdTrans_IterPerExp(m_vardiff[varCoeffEnum[i]],
                                             m_fields[0]->UpdateCoeffs());
            std::stringstream filename;
            filename << "Conductivity_" << aniso_var[i];
            if (m_comm->GetSize() > 1)
            {
                filename << "_P" << m_comm->GetRank();
            }
            filename << ".fld";
            WriteFld(filename.str());
        }

        // Search through the loaded filters and pass the cell model to any
        // CheckpointCellModel filters loaded.
        int k = 0;
        const LibUtilities::FilterMap& f = m_session->GetFilters();
        LibUtilities::FilterMap::const_iterator x;
        for (x = f.begin(); x != f.end(); ++x, ++k)
        {
            if (x->first == "CheckpointCellModel")
            {
                boost::shared_ptr<FilterCheckpointCellModel> c
                    = boost::dynamic_pointer_cast<FilterCheckpointCellModel>(
                                                                m_filters[k]);
                c->SetCellModel(m_cell);
            }
        }

        // Load stimuli
        m_stimulus = Stimulus::LoadStimuli(m_session, m_fields[0]);

        if (!m_explicitDiffusion)
        {
            m_ode.DefineImplicitSolve (&Monodomain::DoImplicitSolve, this);
        }
        m_ode.DefineOdeRhs(&Monodomain::DoOdeRhs, this);
    }

    /**
     *
     */
    Monodomain::~Monodomain()
    {

    }

    /**
     * @param   inarray         Input array.
     * @param   outarray        Output array.
     * @param   time            Current simulation time.
     * @param   lambda          Timestep.
     */
    void Monodomain::DoImplicitSolve(
            const Array<OneD, const Array<OneD, NekDouble> >&inarray,
                  Array<OneD, Array<OneD, NekDouble> >&outarray,
            const NekDouble time,
            const NekDouble lambda)
    {
        int nvariables  = inarray.num_elements();
        int nq          = m_fields[0]->GetNpoints();
        StdRegions::ConstFactorMap factors;
        // lambda = \Delta t
        factors[StdRegions::eFactorLambda] = 1.0/lambda*m_chi*m_capMembrane;

        // We solve ( \nabla^2 - HHlambda ) Y[i] = rhs [i]
        // inarray = input: \hat{rhs} -> output: \hat{Y}
        // outarray = output: nabla^2 \hat{Y}
        // where \hat = modal coeffs
        for (int i = 0; i < nvariables; ++i)
        {
            // Multiply 1.0/timestep
            Vmath::Smul(nq, -factors[StdRegions::eFactorLambda], inarray[i], 1,
                                            m_fields[i]->UpdatePhys(), 1);

            // Solve a system of equations with Helmholtz solver and transform
            // back into physical space.
            m_fields[i]->HelmSolve(m_fields[i]->GetPhys(),
                                   m_fields[i]->UpdateCoeffs(), NullFlagList,
                                   factors, m_vardiff);

            m_fields[i]->BwdTrans( m_fields[i]->GetCoeffs(),
                                   m_fields[i]->UpdatePhys());
            m_fields[i]->SetPhysState(true);

            // Copy the solution vector (required as m_fields must be set).
            outarray[i] = m_fields[i]->GetPhys();
        }
    }

    /**
     *
     */
    void Monodomain::DoOdeRhs(
            const Array<OneD, const  Array<OneD, NekDouble> >&inarray,
                  Array<OneD,        Array<OneD, NekDouble> >&outarray,
            const NekDouble time)
    {
        // Compute I_ion
        m_cell->TimeIntegrate(inarray, outarray, time);

        // Compute I_stim
        for (unsigned int i = 0; i < m_stimulus.size(); ++i)
        {
            m_stimulus[i]->Update(outarray, time);
        }
    }

    /**
     *
     */
    void Monodomain::v_SetInitialConditions(NekDouble initialtime,
                        bool dumpInitialConditions)
    {
        EquationSystem::v_SetInitialConditions(initialtime,
                                               dumpInitialConditions);
        m_cell->Initialise();
    }

    /**
     *
     */
    void Monodomain::v_PrintSummary(std::ostream &out)
    {
        UnsteadySystem::v_PrintSummary(out);
        if (m_session->DefinesFunction("d00") &&
            m_session->GetFunctionType("d00", "intensity")
                    == LibUtilities::eFunctionTypeExpression)
        {
            out << "\tDiffusivity-x   : "
                << m_session->GetFunction("d00", "intensity")->GetExpression()
                << endl;
        }
        if (m_session->DefinesFunction("d11") &&
            m_session->GetFunctionType("d11", "intensity")
                    == LibUtilities::eFunctionTypeExpression)
        {
            out << "\tDiffusivity-x   : "
                << m_session->GetFunction("d11", "intensity")->GetExpression()
                << endl;
        }
        if (m_session->DefinesFunction("d22") &&
            m_session->GetFunctionType("d22", "intensity")
                    == LibUtilities::eFunctionTypeExpression)
        {
            out << "\tDiffusivity-x   : "
                << m_session->GetFunction("d22", "intensity")->GetExpression()
                << endl;
        }
        m_cell->PrintSummary(out);
    }
}
<commit_msg>Tidy up code.<commit_after>///////////////////////////////////////////////////////////////////////////////
//
// File Monodomain.cpp
//
// For more information, please see: http://www.nektar.info
//
// The MIT License
//
// Copyright (c) 2006 Division of Applied Mathematics, Brown University (USA),
// Department of Aeronautics, Imperial College London (UK), and Scientific
// Computing and Imaging Institute, University of Utah (USA).
//
// License for the specific language governing rights and limitations under
// 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.
//
// Description: Monodomain cardiac electrophysiology homogenised model.
//
///////////////////////////////////////////////////////////////////////////////

#include <iostream>

#include <CardiacEPSolver/EquationSystems/Monodomain.h>
#include <CardiacEPSolver/Filters/FilterCheckpointCellModel.h>

namespace Nektar
{
    /**
     * @class Monodomain
     *
     * Base model of cardiac electrophysiology of the form
     * \f{align*}{
     *     \frac{\partial u}{\partial t} = \nabla^2 u + J_{ion},
     * \f}
     * where the reaction term, \f$J_{ion}\f$ is defined by a specific cell
     * model.
     *
     * This implementation, at present, treats the reaction terms explicitly
     * and the diffusive element implicitly.
     */

    /**
     * Registers the class with the Factory.
     */
    string Monodomain::className
            = GetEquationSystemFactory().RegisterCreatorFunction(
                "Monodomain",
                Monodomain::create,
                "Monodomain model of cardiac electrophysiology.");

    /**
     *
     */
    Monodomain::Monodomain(
            const LibUtilities::SessionReaderSharedPtr& pSession)
        : UnsteadySystem(pSession)
    {
    }

    /**
     *
     */
    void Monodomain::v_InitObject()
    {
        UnsteadySystem::v_InitObject();

        m_session->LoadParameter("Chi",        m_chi);
        m_session->LoadParameter("Cm",         m_capMembrane);

        std::string vCellModel;
        m_session->LoadSolverInfo("CELLMODEL", vCellModel, "");

        ASSERTL0(vCellModel != "", "Cell Model not specified.");

        m_cell = GetCellModelFactory().CreateInstance(
                                        vCellModel, m_session, m_fields[0]);

        m_intVariables.push_back(0);

        // Load variable coefficients
        StdRegions::VarCoeffType varCoeffEnum[6] = {
                StdRegions::eVarCoeffD00,
                StdRegions::eVarCoeffD01,
                StdRegions::eVarCoeffD11,
                StdRegions::eVarCoeffD02,
                StdRegions::eVarCoeffD12,
                StdRegions::eVarCoeffD22
        };

        const int nq            = m_fields[0]->GetNpoints();
        const int nVarDiffCmpts = m_spacedim * (m_spacedim + 1) / 2;

        // Allocate storage for variable coeffs and initialize to 1.
        for (int i = 0; i < nVarDiffCmpts; ++i)
        {
            m_vardiff[varCoeffEnum[i]] = Array<OneD, NekDouble>(nq, 1.0);
        }

        // Apply fibre map f \in [0,1], scale to conductivity range
        // [o_min,o_max], specified by the session parameters o_min and o_max
        if (m_session->DefinesFunction("AnisotropicConductivity"))
        {
            if (m_session->DefinesCmdLineArgument("verbose"))
            {
                cout << "Loading Anisotropic Fibre map." << endl;
            }

            std::string aniso_var[3] = {"fx", "fy", "fz"};
            NekDouble   o_min        = m_session->GetParameter("o_min");
            NekDouble   o_max        = m_session->GetParameter("o_max");
            int         k            = 0;

            Array<OneD, NekDouble> vTemp_i;
            Array<OneD, NekDouble> vTemp_j;

            /*
             * Diffusivity matrix D is upper triangular and defined as
             *    d_00   d_01  d_02
             *           d_11  d_12
             *                 d_22
             *
             * Given a principle fibre direction _f_ the diffusivity is given
             * by
             *    d_ij = { D_2 + (D_1 - D_2) f_i f_j   if i==j
             *           {       (D_1 - D_2) f_i f_j   if i!=j
             *
             * The vector _f_ is given in terms of the variables fx,fy,fz in the
             * function AnisotropicConductivity. The values of D_1 and D_2 are
             * the parameters o_max and o_min, respectively.
             */

            // Loop through columns of D
            for (int j = 0; j < m_spacedim; ++j)
            {
                ASSERTL0(m_session->DefinesFunction("AnisotropicConductivity",
                                                    aniso_var[j]),
                         "Function 'AnisotropicConductivity' not correctly "
                         "defined.");
                EvaluateFunction(aniso_var[j], vTemp_j,
                                 "AnisotropicConductivity");

                // Loop through rows of D
                for (int i = 0; i < j + 1; ++i)
                {
                    ASSERTL0(m_session->DefinesFunction(
                                        "AnisotropicConductivity",aniso_var[i]),
                             "Function 'AnisotropicConductivity' not correctly "
                             "defined.");
                    EvaluateFunction(aniso_var[i], vTemp_i,
                                     "AnisotropicConductivity");

                    Vmath::Vmul(nq, vTemp_i, 1, vTemp_j, 1,
                                    m_vardiff[varCoeffEnum[k]], 1);

                    Vmath::Smul(nq, o_max-o_min,
                                    m_vardiff[varCoeffEnum[k]], 1,
                                    m_vardiff[varCoeffEnum[k]], 1);

                    if (i == j)
                    {
                        Vmath::Sadd(nq, o_min,
                                        m_vardiff[varCoeffEnum[k]], 1,
                                        m_vardiff[varCoeffEnum[k]], 1);
                    }

                    ++k;
                }
            }
        }

        // Scale by scar map (range 0->1) derived from intensity map
        // (range d_min -> d_max)
        if (m_session->DefinesFunction("IsotropicConductivity"))
        {
            if (m_session->DefinesCmdLineArgument("verbose"))
            {
                cout << "Loading Isotropic Conductivity map." << endl;
            }

            std::string varName = "intensity";
            NekDouble   f_min   = m_session->GetParameter("d_min");
            NekDouble   f_max   = m_session->GetParameter("d_max");

            Array<OneD, NekDouble> vTemp;
            EvaluateFunction(varName, vTemp, "IsotropicConductivity");

            // Threshold based on d_min, d_max
            for (int j = 0; j < nq; ++j)
            {
                vTemp[j] = (vTemp[j] < f_min ? f_min : vTemp[j]);
                vTemp[j] = (vTemp[j] > f_max ? f_max : vTemp[j]);
            }

            // Rescale to s \in [0,1] (0 maps to d_max, 1 maps to d_min)
            Vmath::Sadd(nq, -f_min, vTemp, 1, vTemp, 1);
            Vmath::Smul(nq, -1.0/(f_max-f_min), vTemp, 1, vTemp, 1);
            Vmath::Sadd(nq, 1.0, vTemp, 1, vTemp, 1);

            // Scale anisotropic conductivity values
            for (int i = 0; i < m_spacedim; ++i)
            {
                Vmath::Vmul(nq, vTemp, 1,
                                m_vardiff[varCoeffEnum[i]], 1,
                                m_vardiff[varCoeffEnum[i]], 1);
            }
        }

        // Write out conductivity values
        for (int i = 0; i < m_spacedim; ++i)
        {
            // Transform variable coefficient and write out to file.
            m_fields[0]->FwdTrans_IterPerExp(m_vardiff[varCoeffEnum[i]],
                                             m_fields[0]->UpdateCoeffs());
            std::stringstream filename;
            filename << "Conductivity_" << aniso_var[i];
            if (m_comm->GetSize() > 1)
            {
                filename << "_P" << m_comm->GetRank();
            }
            filename << ".fld";
            WriteFld(filename.str());
        }

        // Search through the loaded filters and pass the cell model to any
        // CheckpointCellModel filters loaded.
        int k = 0;
        const LibUtilities::FilterMap& f = m_session->GetFilters();
        LibUtilities::FilterMap::const_iterator x;
        for (x = f.begin(); x != f.end(); ++x, ++k)
        {
            if (x->first == "CheckpointCellModel")
            {
                boost::shared_ptr<FilterCheckpointCellModel> c
                    = boost::dynamic_pointer_cast<FilterCheckpointCellModel>(
                                                                m_filters[k]);
                c->SetCellModel(m_cell);
            }
        }

        // Load stimuli
        m_stimulus = Stimulus::LoadStimuli(m_session, m_fields[0]);

        if (!m_explicitDiffusion)
        {
            m_ode.DefineImplicitSolve (&Monodomain::DoImplicitSolve, this);
        }
        m_ode.DefineOdeRhs(&Monodomain::DoOdeRhs, this);
    }

    /**
     *
     */
    Monodomain::~Monodomain()
    {

    }

    /**
     * @param   inarray         Input array.
     * @param   outarray        Output array.
     * @param   time            Current simulation time.
     * @param   lambda          Timestep.
     */
    void Monodomain::DoImplicitSolve(
            const Array<OneD, const Array<OneD, NekDouble> >&inarray,
                  Array<OneD, Array<OneD, NekDouble> >&outarray,
            const NekDouble time,
            const NekDouble lambda)
    {
        int nvariables  = inarray.num_elements();
        int nq          = m_fields[0]->GetNpoints();
        StdRegions::ConstFactorMap factors;
        // lambda = \Delta t
        factors[StdRegions::eFactorLambda] = 1.0/lambda*m_chi*m_capMembrane;

        // We solve ( \nabla^2 - HHlambda ) Y[i] = rhs [i]
        // inarray = input: \hat{rhs} -> output: \hat{Y}
        // outarray = output: nabla^2 \hat{Y}
        // where \hat = modal coeffs
        for (int i = 0; i < nvariables; ++i)
        {
            // Multiply 1.0/timestep
            Vmath::Smul(nq, -factors[StdRegions::eFactorLambda], inarray[i], 1,
                                            m_fields[i]->UpdatePhys(), 1);

            // Solve a system of equations with Helmholtz solver and transform
            // back into physical space.
            m_fields[i]->HelmSolve(m_fields[i]->GetPhys(),
                                   m_fields[i]->UpdateCoeffs(), NullFlagList,
                                   factors, m_vardiff);

            m_fields[i]->BwdTrans( m_fields[i]->GetCoeffs(),
                                   m_fields[i]->UpdatePhys());
            m_fields[i]->SetPhysState(true);

            // Copy the solution vector (required as m_fields must be set).
            outarray[i] = m_fields[i]->GetPhys();
        }
    }

    /**
     *
     */
    void Monodomain::DoOdeRhs(
            const Array<OneD, const  Array<OneD, NekDouble> >&inarray,
                  Array<OneD,        Array<OneD, NekDouble> >&outarray,
            const NekDouble time)
    {
        // Compute I_ion
        m_cell->TimeIntegrate(inarray, outarray, time);

        // Compute I_stim
        for (unsigned int i = 0; i < m_stimulus.size(); ++i)
        {
            m_stimulus[i]->Update(outarray, time);
        }
    }

    /**
     *
     */
    void Monodomain::v_SetInitialConditions(NekDouble initialtime,
                        bool dumpInitialConditions)
    {
        EquationSystem::v_SetInitialConditions(initialtime,
                                               dumpInitialConditions);
        m_cell->Initialise();
    }

    /**
     *
     */
    void Monodomain::v_PrintSummary(std::ostream &out)
    {
        UnsteadySystem::v_PrintSummary(out);
        if (m_session->DefinesFunction("d00") &&
            m_session->GetFunctionType("d00", "intensity")
                    == LibUtilities::eFunctionTypeExpression)
        {
            out << "\tDiffusivity-x   : "
                << m_session->GetFunction("d00", "intensity")->GetExpression()
                << endl;
        }
        if (m_session->DefinesFunction("d11") &&
            m_session->GetFunctionType("d11", "intensity")
                    == LibUtilities::eFunctionTypeExpression)
        {
            out << "\tDiffusivity-x   : "
                << m_session->GetFunction("d11", "intensity")->GetExpression()
                << endl;
        }
        if (m_session->DefinesFunction("d22") &&
            m_session->GetFunctionType("d22", "intensity")
                    == LibUtilities::eFunctionTypeExpression)
        {
            out << "\tDiffusivity-x   : "
                << m_session->GetFunction("d22", "intensity")->GetExpression()
                << endl;
        }
        m_cell->PrintSummary(out);
    }
}
<|endoftext|>