<commit_before>//===- lib/MC/MCMachOStreamer.cpp - Mach-O Object Output ------------===//
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//

#include "llvm/MC/MCStreamer.h"

#include "llvm/MC/MCAssembler.h"
#include "llvm/MC/MCContext.h"
#include "llvm/MC/MCCodeEmitter.h"
#include "llvm/MC/MCExpr.h"
#include "llvm/MC/MCInst.h"
#include "llvm/MC/MCSection.h"
#include "llvm/MC/MCSymbol.h"
#include "llvm/Support/ErrorHandling.h"
#include "llvm/Support/raw_ostream.h"
using namespace llvm;

namespace {

class MCMachOStreamer : public MCStreamer {
  /// SymbolFlags - We store the value for the 'desc' symbol field in the lowest
  /// 16 bits of the implementation defined flags.
  enum SymbolFlags { // See <mach-o/nlist.h>.
    SF_DescFlagsMask                        = 0xFFFF,

    // Reference type flags.
    SF_ReferenceTypeMask                    = 0x0007,
    SF_ReferenceTypeUndefinedNonLazy        = 0x0000,
    SF_ReferenceTypeUndefinedLazy           = 0x0001,
    SF_ReferenceTypeDefined                 = 0x0002,
    SF_ReferenceTypePrivateDefined          = 0x0003,
    SF_ReferenceTypePrivateUndefinedNonLazy = 0x0004,
    SF_ReferenceTypePrivateUndefinedLazy    = 0x0005,

    // Other 'desc' flags.
    SF_NoDeadStrip                          = 0x0020,
    SF_WeakReference                        = 0x0040,
    SF_WeakDefinition                       = 0x0080
  };

private:
  MCAssembler Assembler;
  MCSectionData *CurSectionData;

private:
  MCFragment *getCurrentFragment() const {
    assert(CurSectionData && "No current section!");

    if (!CurSectionData->empty())
      return &CurSectionData->getFragmentList().back();

    return 0;
  }

public:
  MCMachOStreamer(MCContext &Context, TargetAsmBackend &TAB,
                  raw_ostream &_OS, MCCodeEmitter *_Emitter)
    : MCStreamer(Context), Assembler(Context, TAB, *_Emitter, _OS),
      CurSectionData(0) {}
  ~MCMachOStreamer() {}

  const MCExpr *AddValueSymbols(const MCExpr *Value) {
    switch (Value->getKind()) {
    case MCExpr::Target: assert(0 && "Can't handle target exprs yet!");
    case MCExpr::Constant:
      break;

    case MCExpr::Binary: {
      const MCBinaryExpr *BE = cast<MCBinaryExpr>(Value);
      AddValueSymbols(BE->getLHS());
      AddValueSymbols(BE->getRHS());
      break;
    }

    case MCExpr::SymbolRef:
      Assembler.getOrCreateSymbolData(
        cast<MCSymbolRefExpr>(Value)->getSymbol());
      break;

    case MCExpr::Unary:
      AddValueSymbols(cast<MCUnaryExpr>(Value)->getSubExpr());
      break;
    }

    return Value;
  }

  /// @name MCStreamer Interface
  /// @{

  virtual void SwitchSection(const MCSection *Section);
  virtual void EmitLabel(MCSymbol *Symbol);
  virtual void EmitAssemblerFlag(MCAssemblerFlag Flag);
  virtual void EmitAssignment(MCSymbol *Symbol, const MCExpr *Value);
  virtual void EmitSymbolAttribute(MCSymbol *Symbol, MCSymbolAttr Attribute);
  virtual void EmitSymbolDesc(MCSymbol *Symbol, unsigned DescValue);
  virtual void EmitCommonSymbol(MCSymbol *Symbol, uint64_t Size,
                                unsigned ByteAlignment);
  virtual void EmitELFSize(MCSymbol *Symbol, const MCExpr *Value) {
    assert(0 && "macho doesn't support this directive");
  }
  virtual void EmitLocalCommonSymbol(MCSymbol *Symbol, uint64_t Size) {
    assert(0 && "macho doesn't support this directive");
  }
  virtual void EmitZerofill(const MCSection *Section, MCSymbol *Symbol = 0,
                            unsigned Size = 0, unsigned ByteAlignment = 0);
  virtual void EmitBytes(StringRef Data, unsigned AddrSpace);
  virtual void EmitValue(const MCExpr *Value, unsigned Size,unsigned AddrSpace);
  virtual void EmitGPRel32Value(const MCExpr *Value) {
    assert(0 && "macho doesn't support this directive");
  }
  virtual void EmitValueToAlignment(unsigned ByteAlignment, int64_t Value = 0,
                                    unsigned ValueSize = 1,
                                    unsigned MaxBytesToEmit = 0);
  virtual void EmitCodeAlignment(unsigned ByteAlignment,
                                 unsigned MaxBytesToEmit = 0);
  virtual void EmitValueToOffset(const MCExpr *Offset,
                                 unsigned char Value = 0);

  virtual void EmitFileDirective(StringRef Filename) {
    errs() << "FIXME: MCMachoStreamer:EmitFileDirective not implemented\n";
  }
  virtual void EmitDwarfFileDirective(unsigned FileNo, StringRef Filename) {
    errs() << "FIXME: MCMachoStreamer:EmitDwarfFileDirective not implemented\n";
  }

  virtual void EmitInstruction(const MCInst &Inst);
  virtual void Finish();

  /// @}
};

} // end anonymous namespace.

void MCMachOStreamer::SwitchSection(const MCSection *Section) {
  assert(Section && "Cannot switch to a null section!");

  // If already in this section, then this is a noop.
  if (Section == CurSection) return;

  CurSection = Section;
  CurSectionData = &Assembler.getOrCreateSectionData(*Section);
}

void MCMachOStreamer::EmitLabel(MCSymbol *Symbol) {
  assert(Symbol->isUndefined() && "Cannot define a symbol twice!");

  // FIXME: We should also use offsets into Fill fragments.
  MCDataFragment *F = dyn_cast_or_null<MCDataFragment>(getCurrentFragment());
  if (!F)
    F = new MCDataFragment(CurSectionData);

  MCSymbolData &SD = Assembler.getOrCreateSymbolData(*Symbol);
  assert(!SD.getFragment() && "Unexpected fragment on symbol data!");
  SD.setFragment(F);
  SD.setOffset(F->getContents().size());

  // This causes the reference type and weak reference flags to be cleared.
  SD.setFlags(SD.getFlags() & ~(SF_WeakReference | SF_ReferenceTypeMask));

  Symbol->setSection(*CurSection);
}

void MCMachOStreamer::EmitAssemblerFlag(MCAssemblerFlag Flag) {
  switch (Flag) {
  case MCAF_SubsectionsViaSymbols:
    Assembler.setSubsectionsViaSymbols(true);
    return;
  }

  assert(0 && "invalid assembler flag!");
}

void MCMachOStreamer::EmitAssignment(MCSymbol *Symbol, const MCExpr *Value) {
  // Only absolute symbols can be redefined.
  assert((Symbol->isUndefined() || Symbol->isAbsolute()) &&
         "Cannot define a symbol twice!");

  // FIXME: Lift context changes into super class.
  // FIXME: Set associated section.
  Symbol->setValue(AddValueSymbols(Value));
}

void MCMachOStreamer::EmitSymbolAttribute(MCSymbol *Symbol,
                                          MCSymbolAttr Attribute) {
  // Indirect symbols are handled differently, to match how 'as' handles
  // them. This makes writing matching .o files easier.
  if (Attribute == MCSA_IndirectSymbol) {
    // Note that we intentionally cannot use the symbol data here; this is
    // important for matching the string table that 'as' generates.
    IndirectSymbolData ISD;
    ISD.Symbol = Symbol;
    ISD.SectionData = CurSectionData;
    Assembler.getIndirectSymbols().push_back(ISD);
    return;
  }

  // Adding a symbol attribute always introduces the symbol, note that an
  // important side effect of calling getOrCreateSymbolData here is to register
  // the symbol with the assembler.
  MCSymbolData &SD = Assembler.getOrCreateSymbolData(*Symbol);

  // The implementation of symbol attributes is designed to match 'as', but it
  // leaves much to desired. It doesn't really make sense to arbitrarily add and
  // remove flags, but 'as' allows this (in particular, see .desc).
  //
  // In the future it might be worth trying to make these operations more well
  // defined.
  switch (Attribute) {
  case MCSA_Invalid:
  case MCSA_ELF_TypeFunction:
  case MCSA_ELF_TypeIndFunction:
  case MCSA_ELF_TypeObject:
  case MCSA_ELF_TypeTLS:
  case MCSA_ELF_TypeCommon:
  case MCSA_ELF_TypeNoType:
  case MCSA_IndirectSymbol:
  case MCSA_Hidden:
  case MCSA_Internal:
  case MCSA_Protected:
  case MCSA_Weak:
  case MCSA_Local:
    assert(0 && "Invalid symbol attribute for Mach-O!");
    break;

  case MCSA_Global:
    SD.setExternal(true);
    break;

  case MCSA_LazyReference:
    // FIXME: This requires -dynamic.
    SD.setFlags(SD.getFlags() | SF_NoDeadStrip);
    if (Symbol->isUndefined())
      SD.setFlags(SD.getFlags() | SF_ReferenceTypeUndefinedLazy);
    break;

    // Since .reference sets the no dead strip bit, it is equivalent to
    // .no_dead_strip in practice.
  case MCSA_Reference:
  case MCSA_NoDeadStrip:
    SD.setFlags(SD.getFlags() | SF_NoDeadStrip);
    break;

  case MCSA_PrivateExtern:
    SD.setExternal(true);
    SD.setPrivateExtern(true);
    break;

  case MCSA_WeakReference:
    // FIXME: This requires -dynamic.
    if (Symbol->isUndefined())
      SD.setFlags(SD.getFlags() | SF_WeakReference);
    break;

  case MCSA_WeakDefinition:
    // FIXME: 'as' enforces that this is defined and global. The manual claims
    // it has to be in a coalesced section, but this isn't enforced.
    SD.setFlags(SD.getFlags() | SF_WeakDefinition);
    break;
  }
}

void MCMachOStreamer::EmitSymbolDesc(MCSymbol *Symbol, unsigned DescValue) {
  // Encode the 'desc' value into the lowest implementation defined bits.
  assert(DescValue == (DescValue & SF_DescFlagsMask) &&
         "Invalid .desc value!");
  Assembler.getOrCreateSymbolData(*Symbol).setFlags(DescValue&SF_DescFlagsMask);
}

void MCMachOStreamer::EmitCommonSymbol(MCSymbol *Symbol, uint64_t Size,
                                       unsigned ByteAlignment) {
  // FIXME: Darwin 'as' does appear to allow redef of a .comm by itself.
  assert(Symbol->isUndefined() && "Cannot define a symbol twice!");

  MCSymbolData &SD = Assembler.getOrCreateSymbolData(*Symbol);
  SD.setExternal(true);
  SD.setCommon(Size, ByteAlignment);
}

void MCMachOStreamer::EmitZerofill(const MCSection *Section, MCSymbol *Symbol,
                                   unsigned Size, unsigned ByteAlignment) {
  MCSectionData &SectData = Assembler.getOrCreateSectionData(*Section);

  // The symbol may not be present, which only creates the section.
  if (!Symbol)
    return;

  // FIXME: Assert that this section has the zerofill type.

  assert(Symbol->isUndefined() && "Cannot define a symbol twice!");

  MCSymbolData &SD = Assembler.getOrCreateSymbolData(*Symbol);

  MCFragment *F = new MCZeroFillFragment(Size, ByteAlignment, &SectData);
  SD.setFragment(F);

  Symbol->setSection(*Section);

  // Update the maximum alignment on the zero fill section if necessary.
  if (ByteAlignment > SectData.getAlignment())
    SectData.setAlignment(ByteAlignment);
}

void MCMachOStreamer::EmitBytes(StringRef Data, unsigned AddrSpace) {
  MCDataFragment *DF = dyn_cast_or_null<MCDataFragment>(getCurrentFragment());
  if (!DF)
    DF = new MCDataFragment(CurSectionData);
  DF->getContents().append(Data.begin(), Data.end());
}

void MCMachOStreamer::EmitValue(const MCExpr *Value, unsigned Size,
                                unsigned AddrSpace) {
  MCDataFragment *DF = dyn_cast_or_null<MCDataFragment>(getCurrentFragment());
  if (!DF)
    DF = new MCDataFragment(CurSectionData);

  // Avoid fixups when possible.
  int64_t AbsValue;
  if (AddValueSymbols(Value)->EvaluateAsAbsolute(AbsValue)) {
    // FIXME: Endianness assumption.
    for (unsigned i = 0; i != Size; ++i)
      DF->getContents().push_back(uint8_t(AbsValue >> (i * 8)));
  } else {
    DF->addFixup(MCAsmFixup(DF->getContents().size(), *AddValueSymbols(Value),
                            MCFixup::getKindForSize(Size)));
    DF->getContents().resize(DF->getContents().size() + Size, 0);
  }
}

void MCMachOStreamer::EmitValueToAlignment(unsigned ByteAlignment,
                                           int64_t Value, unsigned ValueSize,
                                           unsigned MaxBytesToEmit) {
  if (MaxBytesToEmit == 0)
    MaxBytesToEmit = ByteAlignment;
  new MCAlignFragment(ByteAlignment, Value, ValueSize, MaxBytesToEmit,
                      false /* EmitNops */, CurSectionData);

  // Update the maximum alignment on the current section if necessary.
  if (ByteAlignment > CurSectionData->getAlignment())
    CurSectionData->setAlignment(ByteAlignment);
}

void MCMachOStreamer::EmitCodeAlignment(unsigned ByteAlignment,
                                        unsigned MaxBytesToEmit) {
  if (MaxBytesToEmit == 0)
    MaxBytesToEmit = ByteAlignment;
  // FIXME the 0x90 is the default x86 1 byte nop opcode.
  new MCAlignFragment(ByteAlignment, 0x90, 1, MaxBytesToEmit,
                      true /* EmitNops */, CurSectionData);

  // Update the maximum alignment on the current section if necessary.
  if (ByteAlignment > CurSectionData->getAlignment())
    CurSectionData->setAlignment(ByteAlignment);
}

void MCMachOStreamer::EmitValueToOffset(const MCExpr *Offset,
                                        unsigned char Value) {
  new MCOrgFragment(*Offset, Value, CurSectionData);
}

void MCMachOStreamer::EmitInstruction(const MCInst &Inst) {
  // Scan for values.
  for (unsigned i = 0; i != Inst.getNumOperands(); ++i)
    if (Inst.getOperand(i).isExpr())
      AddValueSymbols(Inst.getOperand(i).getExpr());

  CurSectionData->setHasInstructions(true);

  SmallVector<MCFixup, 4> Fixups;
  SmallString<256> Code;
  raw_svector_ostream VecOS(Code);
  Assembler.getEmitter().EncodeInstruction(Inst, VecOS, Fixups);
  VecOS.flush();

  // Add the fixups and data.
  MCDataFragment *DF = dyn_cast_or_null<MCDataFragment>(getCurrentFragment());
  if (!DF)
    DF = new MCDataFragment(CurSectionData);
  for (unsigned i = 0, e = Fixups.size(); i != e; ++i) {
    MCFixup &F = Fixups[i];
    DF->addFixup(MCAsmFixup(DF->getContents().size()+F.getOffset(),
                            *F.getValue(), F.getKind()));
  }
  DF->getContents().append(Code.begin(), Code.end());
}

void MCMachOStreamer::Finish() {
  Assembler.Finish();
}

MCStreamer *llvm::createMachOStreamer(MCContext &Context, TargetAsmBackend &TAB,
                                      raw_ostream &OS, MCCodeEmitter *CE) {
  return new MCMachOStreamer(Context, TAB, OS, CE);
}
<commit_msg>MC/Mach-O: Factor out getOrCreateDataFragment().<commit_after>//===- lib/MC/MCMachOStreamer.cpp - Mach-O Object Output ------------===//
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//

#include "llvm/MC/MCStreamer.h"

#include "llvm/MC/MCAssembler.h"
#include "llvm/MC/MCContext.h"
#include "llvm/MC/MCCodeEmitter.h"
#include "llvm/MC/MCExpr.h"
#include "llvm/MC/MCInst.h"
#include "llvm/MC/MCSection.h"
#include "llvm/MC/MCSymbol.h"
#include "llvm/Support/ErrorHandling.h"
#include "llvm/Support/raw_ostream.h"
using namespace llvm;

namespace {

class MCMachOStreamer : public MCStreamer {
  /// SymbolFlags - We store the value for the 'desc' symbol field in the lowest
  /// 16 bits of the implementation defined flags.
  enum SymbolFlags { // See <mach-o/nlist.h>.
    SF_DescFlagsMask                        = 0xFFFF,

    // Reference type flags.
    SF_ReferenceTypeMask                    = 0x0007,
    SF_ReferenceTypeUndefinedNonLazy        = 0x0000,
    SF_ReferenceTypeUndefinedLazy           = 0x0001,
    SF_ReferenceTypeDefined                 = 0x0002,
    SF_ReferenceTypePrivateDefined          = 0x0003,
    SF_ReferenceTypePrivateUndefinedNonLazy = 0x0004,
    SF_ReferenceTypePrivateUndefinedLazy    = 0x0005,

    // Other 'desc' flags.
    SF_NoDeadStrip                          = 0x0020,
    SF_WeakReference                        = 0x0040,
    SF_WeakDefinition                       = 0x0080
  };

private:
  MCAssembler Assembler;
  MCSectionData *CurSectionData;

private:
  MCFragment *getCurrentFragment() const {
    assert(CurSectionData && "No current section!");

    if (!CurSectionData->empty())
      return &CurSectionData->getFragmentList().back();

    return 0;
  }

  /// Get a data fragment to write into, creating a new one if the current
  /// fragment is not a data fragment.
  MCDataFragment *getOrCreateDataFragment() const {
    MCDataFragment *F = dyn_cast_or_null<MCDataFragment>(getCurrentFragment());
    if (!F)
      F = new MCDataFragment(CurSectionData);
    return F;
  }

public:
  MCMachOStreamer(MCContext &Context, TargetAsmBackend &TAB,
                  raw_ostream &_OS, MCCodeEmitter *_Emitter)
    : MCStreamer(Context), Assembler(Context, TAB, *_Emitter, _OS),
      CurSectionData(0) {}
  ~MCMachOStreamer() {}

  const MCExpr *AddValueSymbols(const MCExpr *Value) {
    switch (Value->getKind()) {
    case MCExpr::Target: assert(0 && "Can't handle target exprs yet!");
    case MCExpr::Constant:
      break;

    case MCExpr::Binary: {
      const MCBinaryExpr *BE = cast<MCBinaryExpr>(Value);
      AddValueSymbols(BE->getLHS());
      AddValueSymbols(BE->getRHS());
      break;
    }

    case MCExpr::SymbolRef:
      Assembler.getOrCreateSymbolData(
        cast<MCSymbolRefExpr>(Value)->getSymbol());
      break;

    case MCExpr::Unary:
      AddValueSymbols(cast<MCUnaryExpr>(Value)->getSubExpr());
      break;
    }

    return Value;
  }

  /// @name MCStreamer Interface
  /// @{

  virtual void SwitchSection(const MCSection *Section);
  virtual void EmitLabel(MCSymbol *Symbol);
  virtual void EmitAssemblerFlag(MCAssemblerFlag Flag);
  virtual void EmitAssignment(MCSymbol *Symbol, const MCExpr *Value);
  virtual void EmitSymbolAttribute(MCSymbol *Symbol, MCSymbolAttr Attribute);
  virtual void EmitSymbolDesc(MCSymbol *Symbol, unsigned DescValue);
  virtual void EmitCommonSymbol(MCSymbol *Symbol, uint64_t Size,
                                unsigned ByteAlignment);
  virtual void EmitELFSize(MCSymbol *Symbol, const MCExpr *Value) {
    assert(0 && "macho doesn't support this directive");
  }
  virtual void EmitLocalCommonSymbol(MCSymbol *Symbol, uint64_t Size) {
    assert(0 && "macho doesn't support this directive");
  }
  virtual void EmitZerofill(const MCSection *Section, MCSymbol *Symbol = 0,
                            unsigned Size = 0, unsigned ByteAlignment = 0);
  virtual void EmitBytes(StringRef Data, unsigned AddrSpace);
  virtual void EmitValue(const MCExpr *Value, unsigned Size,unsigned AddrSpace);
  virtual void EmitGPRel32Value(const MCExpr *Value) {
    assert(0 && "macho doesn't support this directive");
  }
  virtual void EmitValueToAlignment(unsigned ByteAlignment, int64_t Value = 0,
                                    unsigned ValueSize = 1,
                                    unsigned MaxBytesToEmit = 0);
  virtual void EmitCodeAlignment(unsigned ByteAlignment,
                                 unsigned MaxBytesToEmit = 0);
  virtual void EmitValueToOffset(const MCExpr *Offset,
                                 unsigned char Value = 0);

  virtual void EmitFileDirective(StringRef Filename) {
    errs() << "FIXME: MCMachoStreamer:EmitFileDirective not implemented\n";
  }
  virtual void EmitDwarfFileDirective(unsigned FileNo, StringRef Filename) {
    errs() << "FIXME: MCMachoStreamer:EmitDwarfFileDirective not implemented\n";
  }

  virtual void EmitInstruction(const MCInst &Inst);
  virtual void Finish();

  /// @}
};

} // end anonymous namespace.

void MCMachOStreamer::SwitchSection(const MCSection *Section) {
  assert(Section && "Cannot switch to a null section!");

  // If already in this section, then this is a noop.
  if (Section == CurSection) return;

  CurSection = Section;
  CurSectionData = &Assembler.getOrCreateSectionData(*Section);
}

void MCMachOStreamer::EmitLabel(MCSymbol *Symbol) {
  assert(Symbol->isUndefined() && "Cannot define a symbol twice!");

  // FIXME: This is wasteful, we don't necessarily need to create a data
  // fragment. Instead, we should mark the symbol as pointing into the data
  // fragment if it exists, otherwise we should just queue the label and set its
  // fragment pointer when we emit the next fragment.
  MCDataFragment *F = getOrCreateDataFragment();
  MCSymbolData &SD = Assembler.getOrCreateSymbolData(*Symbol);
  assert(!SD.getFragment() && "Unexpected fragment on symbol data!");
  SD.setFragment(F);
  SD.setOffset(F->getContents().size());

  // This causes the reference type and weak reference flags to be cleared.
  SD.setFlags(SD.getFlags() & ~(SF_WeakReference | SF_ReferenceTypeMask));

  Symbol->setSection(*CurSection);
}

void MCMachOStreamer::EmitAssemblerFlag(MCAssemblerFlag Flag) {
  switch (Flag) {
  case MCAF_SubsectionsViaSymbols:
    Assembler.setSubsectionsViaSymbols(true);
    return;
  }

  assert(0 && "invalid assembler flag!");
}

void MCMachOStreamer::EmitAssignment(MCSymbol *Symbol, const MCExpr *Value) {
  // Only absolute symbols can be redefined.
  assert((Symbol->isUndefined() || Symbol->isAbsolute()) &&
         "Cannot define a symbol twice!");

  // FIXME: Lift context changes into super class.
  // FIXME: Set associated section.
  Symbol->setValue(AddValueSymbols(Value));
}

void MCMachOStreamer::EmitSymbolAttribute(MCSymbol *Symbol,
                                          MCSymbolAttr Attribute) {
  // Indirect symbols are handled differently, to match how 'as' handles
  // them. This makes writing matching .o files easier.
  if (Attribute == MCSA_IndirectSymbol) {
    // Note that we intentionally cannot use the symbol data here; this is
    // important for matching the string table that 'as' generates.
    IndirectSymbolData ISD;
    ISD.Symbol = Symbol;
    ISD.SectionData = CurSectionData;
    Assembler.getIndirectSymbols().push_back(ISD);
    return;
  }

  // Adding a symbol attribute always introduces the symbol, note that an
  // important side effect of calling getOrCreateSymbolData here is to register
  // the symbol with the assembler.
  MCSymbolData &SD = Assembler.getOrCreateSymbolData(*Symbol);

  // The implementation of symbol attributes is designed to match 'as', but it
  // leaves much to desired. It doesn't really make sense to arbitrarily add and
  // remove flags, but 'as' allows this (in particular, see .desc).
  //
  // In the future it might be worth trying to make these operations more well
  // defined.
  switch (Attribute) {
  case MCSA_Invalid:
  case MCSA_ELF_TypeFunction:
  case MCSA_ELF_TypeIndFunction:
  case MCSA_ELF_TypeObject:
  case MCSA_ELF_TypeTLS:
  case MCSA_ELF_TypeCommon:
  case MCSA_ELF_TypeNoType:
  case MCSA_IndirectSymbol:
  case MCSA_Hidden:
  case MCSA_Internal:
  case MCSA_Protected:
  case MCSA_Weak:
  case MCSA_Local:
    assert(0 && "Invalid symbol attribute for Mach-O!");
    break;

  case MCSA_Global:
    SD.setExternal(true);
    break;

  case MCSA_LazyReference:
    // FIXME: This requires -dynamic.
    SD.setFlags(SD.getFlags() | SF_NoDeadStrip);
    if (Symbol->isUndefined())
      SD.setFlags(SD.getFlags() | SF_ReferenceTypeUndefinedLazy);
    break;

    // Since .reference sets the no dead strip bit, it is equivalent to
    // .no_dead_strip in practice.
  case MCSA_Reference:
  case MCSA_NoDeadStrip:
    SD.setFlags(SD.getFlags() | SF_NoDeadStrip);
    break;

  case MCSA_PrivateExtern:
    SD.setExternal(true);
    SD.setPrivateExtern(true);
    break;

  case MCSA_WeakReference:
    // FIXME: This requires -dynamic.
    if (Symbol->isUndefined())
      SD.setFlags(SD.getFlags() | SF_WeakReference);
    break;

  case MCSA_WeakDefinition:
    // FIXME: 'as' enforces that this is defined and global. The manual claims
    // it has to be in a coalesced section, but this isn't enforced.
    SD.setFlags(SD.getFlags() | SF_WeakDefinition);
    break;
  }
}

void MCMachOStreamer::EmitSymbolDesc(MCSymbol *Symbol, unsigned DescValue) {
  // Encode the 'desc' value into the lowest implementation defined bits.
  assert(DescValue == (DescValue & SF_DescFlagsMask) &&
         "Invalid .desc value!");
  Assembler.getOrCreateSymbolData(*Symbol).setFlags(DescValue&SF_DescFlagsMask);
}

void MCMachOStreamer::EmitCommonSymbol(MCSymbol *Symbol, uint64_t Size,
                                       unsigned ByteAlignment) {
  // FIXME: Darwin 'as' does appear to allow redef of a .comm by itself.
  assert(Symbol->isUndefined() && "Cannot define a symbol twice!");

  MCSymbolData &SD = Assembler.getOrCreateSymbolData(*Symbol);
  SD.setExternal(true);
  SD.setCommon(Size, ByteAlignment);
}

void MCMachOStreamer::EmitZerofill(const MCSection *Section, MCSymbol *Symbol,
                                   unsigned Size, unsigned ByteAlignment) {
  MCSectionData &SectData = Assembler.getOrCreateSectionData(*Section);

  // The symbol may not be present, which only creates the section.
  if (!Symbol)
    return;

  // FIXME: Assert that this section has the zerofill type.

  assert(Symbol->isUndefined() && "Cannot define a symbol twice!");

  MCSymbolData &SD = Assembler.getOrCreateSymbolData(*Symbol);

  MCFragment *F = new MCZeroFillFragment(Size, ByteAlignment, &SectData);
  SD.setFragment(F);

  Symbol->setSection(*Section);

  // Update the maximum alignment on the zero fill section if necessary.
  if (ByteAlignment > SectData.getAlignment())
    SectData.setAlignment(ByteAlignment);
}

void MCMachOStreamer::EmitBytes(StringRef Data, unsigned AddrSpace) {
  getOrCreateDataFragment()->getContents().append(Data.begin(), Data.end());
}

void MCMachOStreamer::EmitValue(const MCExpr *Value, unsigned Size,
                                unsigned AddrSpace) {
  MCDataFragment *DF = getOrCreateDataFragment();

  // Avoid fixups when possible.
  int64_t AbsValue;
  if (AddValueSymbols(Value)->EvaluateAsAbsolute(AbsValue)) {
    // FIXME: Endianness assumption.
    for (unsigned i = 0; i != Size; ++i)
      DF->getContents().push_back(uint8_t(AbsValue >> (i * 8)));
  } else {
    DF->addFixup(MCAsmFixup(DF->getContents().size(), *AddValueSymbols(Value),
                            MCFixup::getKindForSize(Size)));
    DF->getContents().resize(DF->getContents().size() + Size, 0);
  }
}

void MCMachOStreamer::EmitValueToAlignment(unsigned ByteAlignment,
                                           int64_t Value, unsigned ValueSize,
                                           unsigned MaxBytesToEmit) {
  if (MaxBytesToEmit == 0)
    MaxBytesToEmit = ByteAlignment;
  new MCAlignFragment(ByteAlignment, Value, ValueSize, MaxBytesToEmit,
                      false /* EmitNops */, CurSectionData);

  // Update the maximum alignment on the current section if necessary.
  if (ByteAlignment > CurSectionData->getAlignment())
    CurSectionData->setAlignment(ByteAlignment);
}

void MCMachOStreamer::EmitCodeAlignment(unsigned ByteAlignment,
                                        unsigned MaxBytesToEmit) {
  if (MaxBytesToEmit == 0)
    MaxBytesToEmit = ByteAlignment;
  // FIXME: The 0x90 is the default x86 1 byte nop opcode.
  new MCAlignFragment(ByteAlignment, 0x90, 1, MaxBytesToEmit,
                      true /* EmitNops */, CurSectionData);

  // Update the maximum alignment on the current section if necessary.
  if (ByteAlignment > CurSectionData->getAlignment())
    CurSectionData->setAlignment(ByteAlignment);
}

void MCMachOStreamer::EmitValueToOffset(const MCExpr *Offset,
                                        unsigned char Value) {
  new MCOrgFragment(*Offset, Value, CurSectionData);
}

void MCMachOStreamer::EmitInstruction(const MCInst &Inst) {
  // Scan for values.
  for (unsigned i = 0; i != Inst.getNumOperands(); ++i)
    if (Inst.getOperand(i).isExpr())
      AddValueSymbols(Inst.getOperand(i).getExpr());

  CurSectionData->setHasInstructions(true);

  SmallVector<MCFixup, 4> Fixups;
  SmallString<256> Code;
  raw_svector_ostream VecOS(Code);
  Assembler.getEmitter().EncodeInstruction(Inst, VecOS, Fixups);
  VecOS.flush();

  // Add the fixups and data.
  MCDataFragment *DF = getOrCreateDataFragment();
  for (unsigned i = 0, e = Fixups.size(); i != e; ++i) {
    MCFixup &F = Fixups[i];
    DF->addFixup(MCAsmFixup(DF->getContents().size()+F.getOffset(),
                            *F.getValue(), F.getKind()));
  }
  DF->getContents().append(Code.begin(), Code.end());
}

void MCMachOStreamer::Finish() {
  Assembler.Finish();
}

MCStreamer *llvm::createMachOStreamer(MCContext &Context, TargetAsmBackend &TAB,
                                      raw_ostream &OS, MCCodeEmitter *CE) {
  return new MCMachOStreamer(Context, TAB, OS, CE);
}
<|endoftext|>


<commit_before>/**
 * Clever programming language
 * Copyright (c) Clever Team
 *
 * This file is distributed under the MIT license. See LICENSE for details.
 */

#include "core/value.h"
#include "core/vm.h"
#include "modules/std/core/array.h"
#include "modules/std/core/function.h"

namespace clever {

TypeObject* ArrayType::allocData(CLEVER_TYPE_CTOR_ARGS) const
{
	ArrayObject* arr = new ArrayObject();
	ValueVector& vec = arr->getData();

	for (size_t i = 0, j = args->size(); i < j; ++i) {
		vec.push_back(args->at(i)->clone());
	}

	return arr;
}

void ArrayType::dump(TypeObject* value, std::ostream& out) const
{
	ArrayObject* arr = static_cast<ArrayObject*>(value);
	ValueVector& vec = arr->getData();

	out << "[";

	for (size_t i = 0, j = vec.size(); i < j; ++i) {
		vec.at(i)->dump(out);
		if (i < j-1) {
			out << ", ";
		}
	}

	out << "]";
}

// Subscript operator
CLEVER_TYPE_AT_OPERATOR(ArrayType::at_op)
{
	ValueVector& arr = CLEVER_GET_OBJECT(ArrayObject*, CLEVER_THIS())->getData();
	long size = arr.size();

	if (!index->isInt()) {
		clever_throw("Invalid array index type");
		return NULL;
	}

	if (index->getInt() < 0 || index->getInt() >= size) {
		clever_throw("Array index out of bound!");
		return NULL;
	}

	Value* result = arr.at(index->getInt());

	// @TODO(Felipe): FIXME
	result->setConst(false);

	clever_addref(result);

	return result;
}

// Array::Array([arg, ...])
CLEVER_METHOD(ArrayType::ctor)
{
	result->setObj(this, allocData(&args));
}

// void Array::append([arg, ... ])
CLEVER_METHOD(ArrayType::append)
{
	if (!clever_check_args("*")) {
		return;
	}

	if (!args.empty()) {
		ValueVector& vec = CLEVER_GET_OBJECT(ArrayObject*, CLEVER_THIS())->getData();

		for (size_t i = 0, j = args.size(); i < j; ++i) {
			vec.push_back(args[i]->clone());
		}
	}
	result->setNull();
}

// int Array::size()
CLEVER_METHOD(ArrayType::size)
{
	if (!clever_check_no_args()) {
		return;
	}

	result->setInt(CLEVER_GET_OBJECT(ArrayObject*, CLEVER_THIS())->getData().size());
}

// mixed Array::at(int position)
CLEVER_METHOD(ArrayType::at)
{
	if (!clever_check_args("i")) {
		return;
	}

	ValueVector& arr = CLEVER_GET_OBJECT(ArrayObject*, CLEVER_THIS())->getData();

	long num = args[0]->getInt();

	if (num < 0 || arr.size() <= size_t(num)) {
		result->setNull();
		return;
	}

	result->copy(arr.at(num));
}

// void Array::reserve(Int size)
CLEVER_METHOD(ArrayType::reserve)
{
	if (!clever_check_args("i")) {
		return;
	}

	ArrayObject* arr = CLEVER_GET_OBJECT(ArrayObject*, CLEVER_THIS());

	result->setNull();

	if (args[0]->getInt() < 0) {
		return;
	}

	arr->getData().reserve(args[0]->getInt());
}

// Array Array::reverse()
// Returns the reverse of this array
CLEVER_METHOD(ArrayType::reverse)
{
	if (!clever_check_no_args()) {
		return;
	}

	ValueVector& vec = CLEVER_GET_OBJECT(ArrayObject*, CLEVER_THIS())->getData();
	ValueVector::reverse_iterator it(vec.rbegin()), end(vec.rend());
	ValueVector rev;

	while (it != end){
		rev.push_back((*it));
		++it;
	}

	result->setObj(this, allocData(&rev));
}

// mixed Array.shift()
// Removes and returns the first element of the array
CLEVER_METHOD(ArrayType::shift)
{
	if (!clever_check_no_args()) {
		return;
	}

	ValueVector& vec = CLEVER_GET_OBJECT(ArrayObject*, CLEVER_THIS())->getData();

	if (vec.empty()) {
		result->setNull();
		return;
	}

	result->copy(vec[0]);
	vec[0]->delRef();

	vec.erase(vec.begin());
}

// mixed Array.pop()
// Removes and returns the last element of the array
CLEVER_METHOD(ArrayType::pop)
{
	if (!clever_check_no_args()) {
		return;
	}

	ValueVector& vec = CLEVER_GET_OBJECT(ArrayObject*, CLEVER_THIS())->getData();

	if (vec.empty()) {
		result->setNull();
		return;
	}

	result->copy(vec[vec.size()-1]);
	vec[vec.size()-1]->delRef();

	vec.erase(vec.end()-1);
}

// Array Array.range(Int start, Int end)
// Returns a range as a new array
CLEVER_METHOD(ArrayType::range)
{
	if (!clever_check_args("ii")) {
		return;
	}

	ValueVector& vec = CLEVER_GET_OBJECT(ArrayObject*, CLEVER_THIS())->getData();

	if (vec.empty()){
		result->setNull();
		return;
	}

	ValueVector ran;
	ValueVector::size_type start = args[0]->getInt(),
		end = args[1]->getInt(),
		size = vec.size();
	bool reverse = (start > end);

	while ((reverse ? (end <= start) : (start <= end))) {
		if (start > size || end > size) {
			break;
		}

		ran.push_back(vec[start]);

		if (reverse) {
			--start;
		} else {
			++start;
		}
	}

	result->setObj(this, allocData(&ran));
}

// Array Array::each(Function callback)
// Calls function once for each element in the array, passing the element as the only parameter to function
// The return values from function are returned in the same order as the array
CLEVER_METHOD(ArrayType::each)
{
	if (!clever_check_args("f")) {
		return;
	}

	Function* func = static_cast<Function*>(args[0]->getObj());
	ValueVector& vec = CLEVER_GET_OBJECT(ArrayObject*, CLEVER_THIS())->getData();
	ValueVector results;

	for (size_t i = 0, j = vec.size(); i < j; ++i) {
		ValueVector tmp_args;

		tmp_args.push_back(vec[i]);

		results.push_back(const_cast<VM*>(vm)->runFunction(func, &tmp_args));
	}

	result->setObj(this, allocData(&results));

	std::for_each(results.begin(), results.end(), clever_delref);
}

// mixed Array.erase(Int position)
// Removes from this array the element at position, returning the value
CLEVER_METHOD(ArrayType::erase)
{
	if (!clever_check_args("i")) {
		return;
	}

	ValueVector& vec = CLEVER_GET_OBJECT(ArrayObject*, CLEVER_THIS())->getData();

	if (vec.empty()) {
		return;
	}

	long num = args[0]->getInt();
	size_t length = vec.size();

	if (num >= 0 && size_t(num) < length) {
		result->copy(vec[num]);

		vec[num]->delRef();

		vec.erase(vec.begin() + num);
	}
}

// Type initialization
CLEVER_TYPE_INIT(ArrayType::init)
{
	setConstructor((MethodPtr)&ArrayType::ctor);

	addMethod(new Function("append",  (MethodPtr)&ArrayType::append));
	addMethod(new Function("size",    (MethodPtr)&ArrayType::size));
	addMethod(new Function("at",      (MethodPtr)&ArrayType::at));
	addMethod(new Function("reserve", (MethodPtr)&ArrayType::reserve));
	addMethod(new Function("reverse", (MethodPtr)&ArrayType::reverse));
	addMethod(new Function("each",    (MethodPtr)&ArrayType::each));
	addMethod(new Function("shift",   (MethodPtr)&ArrayType::shift));
	addMethod(new Function("pop",     (MethodPtr)&ArrayType::pop));
	addMethod(new Function("range",   (MethodPtr)&ArrayType::range));
	addMethod(new Function("erase",	  (MethodPtr)&ArrayType::erase));
}

} // clever
<commit_msg>- Make array items non const<commit_after>/**
 * Clever programming language
 * Copyright (c) Clever Team
 *
 * This file is distributed under the MIT license. See LICENSE for details.
 */

#include "core/value.h"
#include "core/vm.h"
#include "modules/std/core/array.h"
#include "modules/std/core/function.h"

namespace clever {

TypeObject* ArrayType::allocData(CLEVER_TYPE_CTOR_ARGS) const
{
	ArrayObject* arr = new ArrayObject();
	ValueVector& vec = arr->getData();

	for (size_t i = 0, j = args->size(); i < j; ++i) {
		vec.push_back(args->at(i)->clone());
		vec.back()->setConst(false);
	}

	return arr;
}

void ArrayType::dump(TypeObject* value, std::ostream& out) const
{
	ArrayObject* arr = static_cast<ArrayObject*>(value);
	ValueVector& vec = arr->getData();

	out << "[";

	for (size_t i = 0, j = vec.size(); i < j; ++i) {
		vec.at(i)->dump(out);
		if (i < j-1) {
			out << ", ";
		}
	}

	out << "]";
}

// Subscript operator
CLEVER_TYPE_AT_OPERATOR(ArrayType::at_op)
{
	ValueVector& arr = CLEVER_GET_OBJECT(ArrayObject*, CLEVER_THIS())->getData();
	long size = arr.size();

	if (!index->isInt()) {
		clever_throw("Invalid array index type");
		return NULL;
	}

	if (index->getInt() < 0 || index->getInt() >= size) {
		clever_throw("Array index out of bound!");
		return NULL;
	}

	Value* result = arr.at(index->getInt());

	clever_addref(result);

	return result;
}

// Array::Array([arg, ...])
CLEVER_METHOD(ArrayType::ctor)
{
	result->setObj(this, allocData(&args));
}

// void Array::append([arg, ... ])
CLEVER_METHOD(ArrayType::append)
{
	if (!clever_check_args("*")) {
		return;
	}

	if (!args.empty()) {
		ValueVector& vec = CLEVER_GET_OBJECT(ArrayObject*, CLEVER_THIS())->getData();

		for (size_t i = 0, j = args.size(); i < j; ++i) {
			vec.push_back(args[i]->clone());
			vec.back()->setConst(false);
		}
	}
	result->setNull();
}

// int Array::size()
CLEVER_METHOD(ArrayType::size)
{
	if (!clever_check_no_args()) {
		return;
	}

	result->setInt(CLEVER_GET_OBJECT(ArrayObject*, CLEVER_THIS())->getData().size());
}

// mixed Array::at(int position)
CLEVER_METHOD(ArrayType::at)
{
	if (!clever_check_args("i")) {
		return;
	}

	ValueVector& arr = CLEVER_GET_OBJECT(ArrayObject*, CLEVER_THIS())->getData();

	long num = args[0]->getInt();

	if (num < 0 || arr.size() <= size_t(num)) {
		result->setNull();
		return;
	}

	result->copy(arr.at(num));
}

// void Array::reserve(Int size)
CLEVER_METHOD(ArrayType::reserve)
{
	if (!clever_check_args("i")) {
		return;
	}

	ArrayObject* arr = CLEVER_GET_OBJECT(ArrayObject*, CLEVER_THIS());

	result->setNull();

	if (args[0]->getInt() < 0) {
		return;
	}

	arr->getData().reserve(args[0]->getInt());
}

// Array Array::reverse()
// Returns the reverse of this array
CLEVER_METHOD(ArrayType::reverse)
{
	if (!clever_check_no_args()) {
		return;
	}

	ValueVector& vec = CLEVER_GET_OBJECT(ArrayObject*, CLEVER_THIS())->getData();
	ValueVector::reverse_iterator it(vec.rbegin()), end(vec.rend());
	ValueVector rev;

	while (it != end){
		rev.push_back((*it));
		++it;
	}

	result->setObj(this, allocData(&rev));
}

// mixed Array.shift()
// Removes and returns the first element of the array
CLEVER_METHOD(ArrayType::shift)
{
	if (!clever_check_no_args()) {
		return;
	}

	ValueVector& vec = CLEVER_GET_OBJECT(ArrayObject*, CLEVER_THIS())->getData();

	if (vec.empty()) {
		result->setNull();
		return;
	}

	result->copy(vec[0]);
	vec[0]->delRef();

	vec.erase(vec.begin());
}

// mixed Array.pop()
// Removes and returns the last element of the array
CLEVER_METHOD(ArrayType::pop)
{
	if (!clever_check_no_args()) {
		return;
	}

	ValueVector& vec = CLEVER_GET_OBJECT(ArrayObject*, CLEVER_THIS())->getData();

	if (vec.empty()) {
		result->setNull();
		return;
	}

	result->copy(vec[vec.size()-1]);
	vec[vec.size()-1]->delRef();

	vec.erase(vec.end()-1);
}

// Array Array.range(Int start, Int end)
// Returns a range as a new array
CLEVER_METHOD(ArrayType::range)
{
	if (!clever_check_args("ii")) {
		return;
	}

	ValueVector& vec = CLEVER_GET_OBJECT(ArrayObject*, CLEVER_THIS())->getData();

	if (vec.empty()){
		result->setNull();
		return;
	}

	ValueVector ran;
	ValueVector::size_type start = args[0]->getInt(),
		end = args[1]->getInt(),
		size = vec.size();
	bool reverse = (start > end);

	while ((reverse ? (end <= start) : (start <= end))) {
		if (start > size || end > size) {
			break;
		}

		ran.push_back(vec[start]);

		if (reverse) {
			--start;
		} else {
			++start;
		}
	}

	result->setObj(this, allocData(&ran));
}

// Array Array::each(Function callback)
// Calls function once for each element in the array, passing the element as the only parameter to function
// The return values from function are returned in the same order as the array
CLEVER_METHOD(ArrayType::each)
{
	if (!clever_check_args("f")) {
		return;
	}

	Function* func = static_cast<Function*>(args[0]->getObj());
	ValueVector& vec = CLEVER_GET_OBJECT(ArrayObject*, CLEVER_THIS())->getData();
	ValueVector results;

	for (size_t i = 0, j = vec.size(); i < j; ++i) {
		ValueVector tmp_args;

		tmp_args.push_back(vec[i]);

		results.push_back(const_cast<VM*>(vm)->runFunction(func, &tmp_args));
	}

	result->setObj(this, allocData(&results));

	std::for_each(results.begin(), results.end(), clever_delref);
}

// mixed Array.erase(Int position)
// Removes from this array the element at position, returning the value
CLEVER_METHOD(ArrayType::erase)
{
	if (!clever_check_args("i")) {
		return;
	}

	ValueVector& vec = CLEVER_GET_OBJECT(ArrayObject*, CLEVER_THIS())->getData();

	if (vec.empty()) {
		return;
	}

	long num = args[0]->getInt();
	size_t length = vec.size();

	if (num >= 0 && size_t(num) < length) {
		result->copy(vec[num]);

		vec[num]->delRef();

		vec.erase(vec.begin() + num);
	}
}

// Type initialization
CLEVER_TYPE_INIT(ArrayType::init)
{
	setConstructor((MethodPtr)&ArrayType::ctor);

	addMethod(new Function("append",  (MethodPtr)&ArrayType::append));
	addMethod(new Function("size",    (MethodPtr)&ArrayType::size));
	addMethod(new Function("at",      (MethodPtr)&ArrayType::at));
	addMethod(new Function("reserve", (MethodPtr)&ArrayType::reserve));
	addMethod(new Function("reverse", (MethodPtr)&ArrayType::reverse));
	addMethod(new Function("each",    (MethodPtr)&ArrayType::each));
	addMethod(new Function("shift",   (MethodPtr)&ArrayType::shift));
	addMethod(new Function("pop",     (MethodPtr)&ArrayType::pop));
	addMethod(new Function("range",   (MethodPtr)&ArrayType::range));
	addMethod(new Function("erase",	  (MethodPtr)&ArrayType::erase));
}

} // clever
<|endoftext|>


<commit_before>#include <boost/foreach.hpp>
#include <boost/program_options.hpp>
namespace po = boost::program_options;

#include <vw/FileIO.h>
#include <vw/Image.h>
#include <vw/Cartography.h>
using namespace vw;

struct Options {
  Options() : nodata(-1), threshold(-1) {}
  // Input
  std::vector<std::string> input_files;
  double nodata, threshold;
  bool feather;
};

// Operational Code
template <class PixelT>
void shadow_mask_nodata( Options& opt,
                         std::string input,
                         std::string output ) {
  VW_ASSERT( opt.nodata != -1, ArgumentErr() << "Missing user supplied nodata value" );
  typedef typename PixelChannelType<PixelT>::type ChannelT;
  typedef typename MaskedPixelType<PixelT>::type PMaskT;
  if ( opt.threshold < 0 ) {
    ChannelRange<ChannelT> helper;
    opt.threshold = 0.1*helper.max();
  }

  cartography::GeoReference georef;
  cartography::read_georeference(georef, input);
  DiskImageView<PixelT> input_image(input);
  ImageViewRef<PMaskT> masked_input = create_mask(input_image,opt.nodata);
  ImageViewRef<PMaskT> result =
    intersect_mask(masked_input,create_mask(threshold(input_image,opt.threshold)));
  cartography::write_georeferenced_image(output, create_mask(result,opt.nodata),
                                         georef, TerminalProgressCallback("photometrytk","Writing:"));

}

template <class PixelT>
class ThresholdAlphaFunctor : public UnaryReturnSameType {
  typedef typename vw::PixelChannelType<PixelT>::type channel_type;
  double m_threshold;
public:
  ThresholdAlphaFunctor( double t ) : m_threshold(t) {}

  template <class ArgT>
  inline ArgT operator()( ArgT const& arg ) const {
    ArgT copy = arg;
    if ( PixelGray<channel_type>(copy) <= m_threshold ) {
      copy.a() = 0;
    }
    return copy;
  }
};

template <class PixelT>
struct MultiplyAlphaFunctor : public vw::ReturnFixedType<PixelT> {
  template <class Pixel2T>
  inline PixelT operator()( PixelT const& arg1, Pixel2T const& arg2 ) const {
    PixelT copy = arg1;
    copy.a() = float(copy.a()) * float(arg2);
    if ( copy.a() == 0 && arg1.a() != 0 && arg2 != 0 )
      copy.a() = arg1.a();
    return copy;
  }
};

template <class Image1T, class Image2T>
BinaryPerPixelView<Image1T,Image2T,MultiplyAlphaFunctor<typename Image1T::pixel_type> >
inline multiply_alpha( ImageViewBase<Image1T> const& image,
                       ImageViewBase<Image2T> const& multiply ) {
  typedef MultiplyAlphaFunctor<typename Image1T::pixel_type> FuncT;
  return BinaryPerPixelView<Image1T,Image2T,FuncT>( image.impl(), multiply.impl(), FuncT() );
}

template <class PixelT>
void shadow_mask_alpha( Options& opt,
                        std::string input,
                        std::string output ) {
  typedef typename PixelChannelType<PixelT>::type ChannelT;
  typedef typename PixelWithoutAlpha<PixelT>::type PixelNoAT;
  ChannelRange<ChannelT> helper;
  if ( opt.threshold < 0 ) {
    opt.threshold = 0.1*helper.max();
  }

  cartography::GeoReference georef;
  cartography::read_georeference(georef, input);
  DiskImageView<PixelT> input_image(input);
  if ( opt.feather ) {
    ImageViewRef<PixelNoAT> invert_holes =
      threshold(apply_mask(alpha_to_mask(input_image),helper.max()),
                opt.threshold,0,helper.max());
    ImageView<int32> dist = grassfire(invert_holes);
    ImageViewRef<double> alpha_mod = clamp(channel_cast<double>(dist)/15.0,1.0);
    ImageViewRef<PixelT> result = multiply_alpha( input_image, alpha_mod );

    cartography::write_georeferenced_image(output, result, georef,
                                           TerminalProgressCallback("photometrytk","Writing:"));
  } else {
    ImageViewRef<PixelT> result =
      UnaryPerPixelView<DiskImageView<PixelT>,ThresholdAlphaFunctor<PixelT> >(input_image,ThresholdAlphaFunctor<PixelT>(opt.threshold));

    cartography::write_georeferenced_image(output, result, georef,
                                           TerminalProgressCallback("photometrytk","Writing:"));
  }
}

// Code for handing input
void handle_arguments( int argc, char *argv[], Options& opt ) {
  po::options_description general_options("");
  general_options.add_options()
    ("nodata-value", po::value<double>(&opt.nodata), "Value that is nodata in the input image. Not used if input has alpha.")
    ("threshold,t", po::value<double>(&opt.threshold), "Value used to detect shadows.")
    ("feather", "Feather pre-existing alpha around the newly masked shadows. Only for images with alpha already.")
    ("help,h", "Display this help message");

  po::options_description positional("");
  positional.add_options()
    ("input-files", po::value<std::vector<std::string> >(&opt.input_files));

  po::positional_options_description positional_desc;
  positional_desc.add("input-files", -1);

  po::options_description all_options;
  all_options.add(general_options).add(positional);

  po::variables_map vm;
  try {
    po::store( po::command_line_parser( argc, argv ).options(all_options).positional(positional_desc).run(), vm );
    po::notify( vm );
  } catch (po::error &e) {
    vw_throw( ArgumentErr() << "Error parsing input:\n\t"
              << e.what() << general_options );
  }

  std::ostringstream usage;
  usage << "Usage: " << argv[0] << " [options] <image-files>\n";
  opt.feather = vm.count("feather");

  if ( vm.count("help") )
    vw_throw( ArgumentErr() << usage.str() << general_options );
  if ( opt.input_files.empty() )
    vw_throw( ArgumentErr() << "Missing input files!\n"
              << usage.str() << general_options );
}

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

  Options opt;
  try {
    handle_arguments( argc, argv, opt );

    BOOST_FOREACH( const std::string& input, opt.input_files ) {

      // Determining the format of the input
      DiskImageResource *rsrc = DiskImageResource::open(input);
      ChannelTypeEnum channel_type = rsrc->channel_type();
      PixelFormatEnum pixel_format = rsrc->pixel_format();
      delete rsrc;

      vw_out() << "Loading: " << input << "\n";
      size_t pt_idx = input.rfind(".");
      std::string output = input.substr(0,pt_idx)+"_shdw" +
        input.substr(pt_idx,input.size()-pt_idx);

      switch (pixel_format) {
      case VW_PIXEL_GRAY:
        switch (channel_type) {
        case VW_CHANNEL_UINT8:
          shadow_mask_nodata<PixelGray<uint8> >( opt, input, output ); break;
        case VW_CHANNEL_INT16:
          shadow_mask_nodata<PixelGray<int16> >( opt, input, output ); break;
        case VW_CHANNEL_UINT16:
          shadow_mask_nodata<PixelGray<uint16> >( opt, input, output ); break;
        default:
          shadow_mask_nodata<PixelGray<float32> >( opt, input, output ); break;
        }
        break;
      case VW_PIXEL_GRAYA:
        switch (channel_type) {
        case VW_CHANNEL_UINT8:
          shadow_mask_alpha<PixelGrayA<uint8> >( opt, input, output ); break;
        case VW_CHANNEL_INT16:
          shadow_mask_alpha<PixelGrayA<int16> >( opt, input, output ); break;
        case VW_CHANNEL_UINT16:
          shadow_mask_alpha<PixelGrayA<uint16> >( opt, input, output ); break;
        default:
          shadow_mask_alpha<PixelGrayA<float32> >( opt, input, output ); break;
        }
        break;
      case VW_PIXEL_RGB:
        switch (channel_type) {
        case VW_CHANNEL_UINT8:
          shadow_mask_nodata<PixelRGB<uint8> >( opt, input, output ); break;
        case VW_CHANNEL_INT16:
          shadow_mask_nodata<PixelRGB<int16> >( opt, input, output ); break;
        case VW_CHANNEL_UINT16:
          shadow_mask_nodata<PixelRGB<uint16> >( opt, input, output ); break;
        default:
          shadow_mask_nodata<PixelRGB<float32> >( opt, input, output ); break;
        }
        break;
      default:
        switch (channel_type) {
        case VW_CHANNEL_UINT8:
          shadow_mask_alpha<PixelRGBA<uint8> >( opt, input, output ); break;
        case VW_CHANNEL_INT16:
          shadow_mask_alpha<PixelRGBA<int16> >( opt, input, output ); break;
        case VW_CHANNEL_UINT16:
          shadow_mask_alpha<PixelRGBA<uint16> >( opt, input, output ); break;
        default:
          shadow_mask_alpha<PixelRGBA<float32> >( opt, input, output ); break;
        }
        break;
      }

    }

  } catch ( const ArgumentErr& e ) {
    vw_out() << e.what() << std::endl;
    return 1;
  } catch ( const Exception& e ) {
    std::cerr << "Error: " << e.what() << std::endl;
    return 1;
  }

  return 0;
}
<commit_msg>modify shadow_mask to have a slow blend<commit_after>#include <boost/foreach.hpp>
#include <boost/program_options.hpp>
namespace po = boost::program_options;

#include <vw/FileIO.h>
#include <vw/Image.h>
#include <vw/Cartography.h>
using namespace vw;

struct Options {
  Options() : nodata(-1), threshold(-1) {}
  // Input
  std::vector<std::string> input_files;
  double nodata, threshold;
  bool feather;
};

// Operational Code
template <class PixelT>
void shadow_mask_nodata( Options& opt,
                         std::string input,
                         std::string output ) {
  VW_ASSERT( opt.nodata != -1, ArgumentErr() << "Missing user supplied nodata value" );
  typedef typename PixelChannelType<PixelT>::type ChannelT;
  typedef typename MaskedPixelType<PixelT>::type PMaskT;
  if ( opt.threshold < 0 ) {
    ChannelRange<ChannelT> helper;
    opt.threshold = 0.1*helper.max();
  }

  cartography::GeoReference georef;
  cartography::read_georeference(georef, input);
  DiskImageView<PixelT> input_image(input);
  ImageViewRef<PMaskT> masked_input = create_mask(input_image,opt.nodata);
  ImageViewRef<PMaskT> result =
    intersect_mask(masked_input,create_mask(threshold(input_image,opt.threshold)));
  cartography::write_georeferenced_image(output, create_mask(result,opt.nodata),
                                         georef, TerminalProgressCallback("photometrytk","Writing:"));

}

template <class PixelT>
class ThresholdAlphaFunctor : public UnaryReturnSameType {
  typedef typename vw::PixelChannelType<PixelT>::type channel_type;
  double m_threshold;
public:
  ThresholdAlphaFunctor( double t ) : m_threshold(t) {}

  template <class ArgT>
  inline ArgT operator()( ArgT const& arg ) const {
    ArgT copy = arg;
    if ( PixelGray<channel_type>(copy) <= m_threshold ) {
      copy.a() = 0;
    }
    return copy;
  }
};

template <class PixelT>
struct MultiplyAlphaFunctor : public vw::ReturnFixedType<PixelT> {
  template <class Pixel2T>
  inline PixelT operator()( PixelT const& arg1, Pixel2T const& arg2 ) const {
    PixelT copy = arg1;
    copy.a() = double(copy.a()) * arg2;
    if ( !boost::is_floating_point<typename CompoundChannelType<PixelT>::type>::value &&
         copy.a() == 0 && arg1.a() != 0 && arg2 != 0 )
      copy.a() = 1;
    return copy;
  }
};

template <class PixelT>
void shadow_mask_alpha( Options& opt,
                        std::string input,
                        std::string output ) {
  typedef typename PixelChannelType<PixelT>::type ChannelT;
  typedef typename PixelWithoutAlpha<PixelT>::type PixelNoAT;
  ChannelRange<ChannelT> helper;
  if ( opt.threshold < 0 ) {
    opt.threshold = 0.1*helper.max();
  }

  cartography::GeoReference georef;
  cartography::read_georeference(georef, input);
  DiskImageView<PixelT> input_image(input);
  if ( opt.feather ) {
    ImageViewRef<PixelNoAT> invert_holes =
      threshold(apply_mask(alpha_to_mask(input_image),helper.max()),
                opt.threshold,0,helper.max());
    ImageView<int32> dist = grassfire(invert_holes);
    ImageViewRef<double> alpha_mod =
      clamp(channel_cast<double>(dist)/40.0,1.0);
    ImageViewRef<PixelT> result = per_pixel_filter( input_image, alpha_mod, MultiplyAlphaFunctor<PixelT>() );

    cartography::write_georeferenced_image(output, result, georef,
                                           TerminalProgressCallback("photometrytk","Writing:"));
  } else {
    ImageViewRef<PixelT> result =
      per_pixel_filter( input_image, ThresholdAlphaFunctor<PixelT>(opt.threshold) );

    cartography::write_georeferenced_image(output, result, georef,
                                           TerminalProgressCallback("photometrytk","Writing:"));
  }
}

// Code for handing input
void handle_arguments( int argc, char *argv[], Options& opt ) {
  po::options_description general_options("");
  general_options.add_options()
    ("nodata-value", po::value<double>(&opt.nodata), "Value that is nodata in the input image. Not used if input has alpha.")
    ("threshold,t", po::value<double>(&opt.threshold), "Value used to detect shadows.")
    ("feather", "Feather pre-existing alpha around the newly masked shadows. Only for images with alpha already.")
    ("help,h", "Display this help message");

  po::options_description positional("");
  positional.add_options()
    ("input-files", po::value<std::vector<std::string> >(&opt.input_files));

  po::positional_options_description positional_desc;
  positional_desc.add("input-files", -1);

  po::options_description all_options;
  all_options.add(general_options).add(positional);

  po::variables_map vm;
  try {
    po::store( po::command_line_parser( argc, argv ).options(all_options).positional(positional_desc).run(), vm );
    po::notify( vm );
  } catch (po::error &e) {
    vw_throw( ArgumentErr() << "Error parsing input:\n\t"
              << e.what() << general_options );
  }

  std::ostringstream usage;
  usage << "Usage: " << argv[0] << " [options] <image-files>\n";
  opt.feather = vm.count("feather");

  if ( vm.count("help") )
    vw_throw( ArgumentErr() << usage.str() << general_options );
  if ( opt.input_files.empty() )
    vw_throw( ArgumentErr() << "Missing input files!\n"
              << usage.str() << general_options );
}

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

  Options opt;
  try {
    handle_arguments( argc, argv, opt );

    BOOST_FOREACH( const std::string& input, opt.input_files ) {

      // Determining the format of the input
      DiskImageResource *rsrc = DiskImageResource::open(input);
      ChannelTypeEnum channel_type = rsrc->channel_type();
      PixelFormatEnum pixel_format = rsrc->pixel_format();
      delete rsrc;

      vw_out() << "Loading: " << input << "\n";
      size_t pt_idx = input.rfind(".");
      std::string output = input.substr(0,pt_idx)+"_shdw" +
        input.substr(pt_idx,input.size()-pt_idx);

      switch (pixel_format) {
      case VW_PIXEL_GRAY:
        switch (channel_type) {
        case VW_CHANNEL_UINT8:
          shadow_mask_nodata<PixelGray<uint8> >( opt, input, output ); break;
        case VW_CHANNEL_INT16:
          shadow_mask_nodata<PixelGray<int16> >( opt, input, output ); break;
        case VW_CHANNEL_UINT16:
          shadow_mask_nodata<PixelGray<uint16> >( opt, input, output ); break;
        default:
          shadow_mask_nodata<PixelGray<float32> >( opt, input, output ); break;
        }
        break;
      case VW_PIXEL_GRAYA:
        switch (channel_type) {
        case VW_CHANNEL_UINT8:
          shadow_mask_alpha<PixelGrayA<uint8> >( opt, input, output ); break;
        case VW_CHANNEL_INT16:
          shadow_mask_alpha<PixelGrayA<int16> >( opt, input, output ); break;
        case VW_CHANNEL_UINT16:
          shadow_mask_alpha<PixelGrayA<uint16> >( opt, input, output ); break;
        default:
          shadow_mask_alpha<PixelGrayA<float32> >( opt, input, output ); break;
        }
        break;
      case VW_PIXEL_RGB:
        switch (channel_type) {
        case VW_CHANNEL_UINT8:
          shadow_mask_nodata<PixelRGB<uint8> >( opt, input, output ); break;
        case VW_CHANNEL_INT16:
          shadow_mask_nodata<PixelRGB<int16> >( opt, input, output ); break;
        case VW_CHANNEL_UINT16:
          shadow_mask_nodata<PixelRGB<uint16> >( opt, input, output ); break;
        default:
          shadow_mask_nodata<PixelRGB<float32> >( opt, input, output ); break;
        }
        break;
      default:
        switch (channel_type) {
        case VW_CHANNEL_UINT8:
          shadow_mask_alpha<PixelRGBA<uint8> >( opt, input, output ); break;
        case VW_CHANNEL_INT16:
          shadow_mask_alpha<PixelRGBA<int16> >( opt, input, output ); break;
        case VW_CHANNEL_UINT16:
          shadow_mask_alpha<PixelRGBA<uint16> >( opt, input, output ); break;
        default:
          shadow_mask_alpha<PixelRGBA<float32> >( opt, input, output ); break;
        }
        break;
      }

    }

  } catch ( const ArgumentErr& e ) {
    vw_out() << e.what() << std::endl;
    return 1;
  } catch ( const Exception& e ) {
    std::cerr << "Error: " << e.what() << std::endl;
    return 1;
  }

  return 0;
}
<|endoftext|>


<commit_before>#ifndef ITER_GROUP_BY_HPP_
#define ITER_GROUP_BY_HPP_

#include "iterbase.hpp"

#include <type_traits>
#include <utility>
#include <iterator>
#include <initializer_list>

namespace iter {

    template <typename Container, typename KeyFunc>
    class GroupBy;

    template <typename Container, typename KeyFunc>
    GroupBy<Container, KeyFunc> groupby(Container&&, KeyFunc);

    template <typename T, typename KeyFunc>
    GroupBy<std::initializer_list<T>, KeyFunc> groupby(
            std::initializer_list<T>, KeyFunc);

    template <typename Container, typename KeyFunc>
    class GroupBy  {
        private:
            Container container;
            KeyFunc key_func;

            friend GroupBy groupby<Container, KeyFunc>(Container&&, KeyFunc);

            template <typename T, typename KF>
            friend GroupBy<std::initializer_list<T>, KF> groupby(
                    std::initializer_list<T>, KF);

            using key_func_ret = typename
                std::result_of<KeyFunc(iterator_deref<Container>)>::type;

            GroupBy(Container&& container, KeyFunc key_func)
                : container(std::forward<Container>(container)),
                key_func(key_func)
            { }

        public:
            GroupBy() = delete;
            GroupBy(const GroupBy&) = delete;
            GroupBy& operator=(const GroupBy&) = delete;
            GroupBy& operator=(GroupBy&&) = delete;

            GroupBy(GroupBy&&) = default;

            class Iterator;
            class Group;

        private:
            using KeyGroupPair =
                std::pair<key_func_ret, Group>;
        public:

            class Iterator
                : public std::iterator<std::input_iterator_tag, KeyGroupPair>
            {
                private:
                    iterator_type<Container> sub_iter;
                    iterator_type<Container> sub_iter_peek;
                    iterator_type<Container> sub_end;
                    KeyFunc key_func;

                public:
                    Iterator (iterator_type<Container> si,
                              iterator_type<Container> end,
                              KeyFunc key_func)
                        : sub_iter{si},
                        sub_end{end},
                        key_func(key_func)
                    { }

                    KeyGroupPair operator*() {
                        return {
                            this->key_func(*this->sub_iter),
                            Group{*this, this->key_func(*this->sub_iter)}
                        };
                    }

                    Iterator& operator++() {
                        return *this;
                    }

                    Iterator operator++(int) {
                        auto ret = *this;
                        ++*this;
                        return ret;
                    }

                    bool operator!=(const Iterator& other) const {
                        return this->sub_iter != other.sub_iter;
                    }

                    bool operator==(const Iterator& other) const {
                        return !(*this != other);
                    }

                    void increment_iterator() {
                        if (this->sub_iter != this->sub_end) {
                            ++this->sub_iter;
                        }
                    }

                    bool exhausted() const {
                        return !(this->sub_iter != this->sub_end);
                    }

                    iterator_deref<Container> current() {
                        return *this->sub_iter;
                    }

                    key_func_ret next_key() {
                        return this->key_func(*this->sub_iter);
                    }
            };

            class Group {
                private:
                    friend Iterator;
                    friend class GroupIterator;
                    Iterator& owner;
                    key_func_ret key;

                    // completed is set if a Group is iterated through
                    // completely.  It is checked in the destructor, and
                    // if the Group has not been completed, the destructor
                    // exhausts it.  This ensures that the next Group starts
                    // at the correct position when the user short-circuits
                    // iteration over a Group.
                    // The move constructor sets the rvalue's completed
                    // attribute to true, so its destructor doesn't do anything
                    // when called.
                    bool completed = false;

                    Group(Iterator& owner, key_func_ret key) :
                        owner(owner),
                        key(key)
                    { }

                public:
                    ~Group() {
                        if (!this->completed) {
                            for (auto iter = this->begin(), end = this->end();
                                    iter != end;
                                    ++iter) { }
                        }
                    }

                    // move-constructible, non-copy-constructible,
                    // non-assignable
                    Group() = delete;
                    Group(const Group&) = delete;
                    Group& operator=(const Group&) = delete;
                    Group& operator=(Group&&) = delete;

                    Group(Group&& other)
                            : owner{other.owner},
                            key{other.key},
                            completed{other.completed} {
                        other.completed = true;
                    }

                    class GroupIterator
                        : public std::iterator<std::input_iterator_tag,
                                iterator_traits_deref<Container>>
                    {
                        private:
                            key_func_ret key;
                            Group *group_p;

                            bool not_at_end() {
                                return !this->group_p->owner.exhausted()&&
                                    this->group_p->owner.next_key() == this->key;
                            }

                        public:
                            GroupIterator(Group *in_group_p,
                                          key_func_ret key)
                                : key{key},
                                group_p{in_group_p}
                            { }

                            bool operator!=(const GroupIterator& other) const {
                                return !(*this == other);
                            }

                            bool operator==(const GroupIterator& other) const {
                                return this->group_p == other.group_p;
                            }

                            GroupIterator& operator++() {
                                this->group_p->owner.increment_iterator();
                                if (!this->not_at_end()) {
                                    this->group_p->completed = true;
                                    this->group_p = nullptr;
                                }
                                return *this;
                            }

                            GroupIterator operator++(int) {
                                auto ret = *this;
                                ++*this;
                                return ret;
                            }

                            iterator_deref<Container> operator*() {
                                return this->group_p->owner.current();
                            }
                    };

                    GroupIterator begin() {
                        return {this, key};
                    }

                    GroupIterator end() {
                        return {nullptr, key};
                    }

            };

            Iterator begin() {
                return {std::begin(this->container),
                        std::end(this->container),
                        this->key_func};
            }

            Iterator end() {
                return {std::end(this->container),
                        std::end(this->container),
                        this->key_func};
            }

    };

    // Takes something and returns it, used for default key of comparing
    // items in the sequence directly
    template <typename Container>
    class ItemReturner {
        public:
            iterator_deref<Container> operator() (
                    iterator_deref<Container> item) const {
                return item;
            }
    };

    template <typename Container, typename KeyFunc>
    GroupBy<Container, KeyFunc> groupby(
            Container&& container, KeyFunc key_func) {
        return {std::forward<Container>(container), key_func};
    }

    template <typename Container>
    auto groupby(Container&& container) ->
            decltype(groupby(std::forward<Container>(container),
                        ItemReturner<Container>())) {
        return groupby(std::forward<Container>(container),
                ItemReturner<Container>());
    }

    template <typename T, typename KeyFunc>
    GroupBy<std::initializer_list<T>, KeyFunc> groupby(
            std::initializer_list<T> il, KeyFunc key_func) {
        return {std::move(il), key_func};
    }

    template <typename T>
    auto groupby(std::initializer_list<T> il) ->
            decltype(groupby(std::move(il),
                        ItemReturner<std::initializer_list<T>>())) {
        return groupby(
                std::move(il),
                ItemReturner<std::initializer_list<T>>());
    }

}

#endif
<commit_msg>uses c++14 type aliases<commit_after>#ifndef ITER_GROUP_BY_HPP_
#define ITER_GROUP_BY_HPP_

#include "iterbase.hpp"

#include <type_traits>
#include <utility>
#include <iterator>
#include <initializer_list>

namespace iter {

    template <typename Container, typename KeyFunc>
    class GroupBy;

    template <typename Container, typename KeyFunc>
    GroupBy<Container, KeyFunc> groupby(Container&&, KeyFunc);

    template <typename T, typename KeyFunc>
    GroupBy<std::initializer_list<T>, KeyFunc> groupby(
            std::initializer_list<T>, KeyFunc);

    template <typename Container, typename KeyFunc>
    class GroupBy  {
        private:
            Container container;
            KeyFunc key_func;

            friend GroupBy groupby<Container, KeyFunc>(Container&&, KeyFunc);

            template <typename T, typename KF>
            friend GroupBy<std::initializer_list<T>, KF> groupby(
                    std::initializer_list<T>, KF);

            using key_func_ret =
                std::result_of_t<KeyFunc(iterator_deref<Container>)>;

            GroupBy(Container&& container, KeyFunc key_func)
                : container(std::forward<Container>(container)),
                key_func(key_func)
            { }

        public:
            GroupBy() = delete;
            GroupBy(const GroupBy&) = delete;
            GroupBy& operator=(const GroupBy&) = delete;
            GroupBy& operator=(GroupBy&&) = delete;

            GroupBy(GroupBy&&) = default;

            class Iterator;
            class Group;

        private:
            using KeyGroupPair =
                std::pair<key_func_ret, Group>;
        public:

            class Iterator
                : public std::iterator<std::input_iterator_tag, KeyGroupPair>
            {
                private:
                    iterator_type<Container> sub_iter;
                    iterator_type<Container> sub_iter_peek;
                    iterator_type<Container> sub_end;
                    KeyFunc key_func;

                public:
                    Iterator (iterator_type<Container> si,
                              iterator_type<Container> end,
                              KeyFunc key_func)
                        : sub_iter{si},
                        sub_end{end},
                        key_func(key_func)
                    { }

                    KeyGroupPair operator*() {
                        return {
                            this->key_func(*this->sub_iter),
                            Group{*this, this->key_func(*this->sub_iter)}
                        };
                    }

                    Iterator& operator++() {
                        return *this;
                    }

                    Iterator operator++(int) {
                        auto ret = *this;
                        ++*this;
                        return ret;
                    }

                    bool operator!=(const Iterator& other) const {
                        return this->sub_iter != other.sub_iter;
                    }

                    bool operator==(const Iterator& other) const {
                        return !(*this != other);
                    }

                    void increment_iterator() {
                        if (this->sub_iter != this->sub_end) {
                            ++this->sub_iter;
                        }
                    }

                    bool exhausted() const {
                        return !(this->sub_iter != this->sub_end);
                    }

                    iterator_deref<Container> current() {
                        return *this->sub_iter;
                    }

                    key_func_ret next_key() {
                        return this->key_func(*this->sub_iter);
                    }
            };

            class Group {
                private:
                    friend Iterator;
                    friend class GroupIterator;
                    Iterator& owner;
                    key_func_ret key;

                    // completed is set if a Group is iterated through
                    // completely.  It is checked in the destructor, and
                    // if the Group has not been completed, the destructor
                    // exhausts it.  This ensures that the next Group starts
                    // at the correct position when the user short-circuits
                    // iteration over a Group.
                    // The move constructor sets the rvalue's completed
                    // attribute to true, so its destructor doesn't do anything
                    // when called.
                    bool completed = false;

                    Group(Iterator& owner, key_func_ret key) :
                        owner(owner),
                        key(key)
                    { }

                public:
                    ~Group() {
                        if (!this->completed) {
                            for (auto iter = this->begin(), end = this->end();
                                    iter != end;
                                    ++iter) { }
                        }
                    }

                    // move-constructible, non-copy-constructible,
                    // non-assignable
                    Group() = delete;
                    Group(const Group&) = delete;
                    Group& operator=(const Group&) = delete;
                    Group& operator=(Group&&) = delete;

                    Group(Group&& other)
                            : owner{other.owner},
                            key{other.key},
                            completed{other.completed} {
                        other.completed = true;
                    }

                    class GroupIterator
                        : public std::iterator<std::input_iterator_tag,
                                iterator_traits_deref<Container>>
                    {
                        private:
                            key_func_ret key;
                            Group *group_p;

                            bool not_at_end() {
                                return !this->group_p->owner.exhausted()&&
                                    this->group_p->owner.next_key() == this->key;
                            }

                        public:
                            GroupIterator(Group *in_group_p,
                                          key_func_ret key)
                                : key{key},
                                group_p{in_group_p}
                            { }

                            bool operator!=(const GroupIterator& other) const {
                                return !(*this == other);
                            }

                            bool operator==(const GroupIterator& other) const {
                                return this->group_p == other.group_p;
                            }

                            GroupIterator& operator++() {
                                this->group_p->owner.increment_iterator();
                                if (!this->not_at_end()) {
                                    this->group_p->completed = true;
                                    this->group_p = nullptr;
                                }
                                return *this;
                            }

                            GroupIterator operator++(int) {
                                auto ret = *this;
                                ++*this;
                                return ret;
                            }

                            iterator_deref<Container> operator*() {
                                return this->group_p->owner.current();
                            }
                    };

                    GroupIterator begin() {
                        return {this, key};
                    }

                    GroupIterator end() {
                        return {nullptr, key};
                    }

            };

            Iterator begin() {
                return {std::begin(this->container),
                        std::end(this->container),
                        this->key_func};
            }

            Iterator end() {
                return {std::end(this->container),
                        std::end(this->container),
                        this->key_func};
            }

    };

    // Takes something and returns it, used for default key of comparing
    // items in the sequence directly
    template <typename Container>
    class ItemReturner {
        public:
            iterator_deref<Container> operator() (
                    iterator_deref<Container> item) const {
                return item;
            }
    };

    template <typename Container, typename KeyFunc>
    GroupBy<Container, KeyFunc> groupby(
            Container&& container, KeyFunc key_func) {
        return {std::forward<Container>(container), key_func};
    }

    template <typename Container>
    auto groupby(Container&& container) ->
            decltype(groupby(std::forward<Container>(container),
                        ItemReturner<Container>())) {
        return groupby(std::forward<Container>(container),
                ItemReturner<Container>());
    }

    template <typename T, typename KeyFunc>
    GroupBy<std::initializer_list<T>, KeyFunc> groupby(
            std::initializer_list<T> il, KeyFunc key_func) {
        return {std::move(il), key_func};
    }

    template <typename T>
    auto groupby(std::initializer_list<T> il) ->
            decltype(groupby(std::move(il),
                        ItemReturner<std::initializer_list<T>>())) {
        return groupby(
                std::move(il),
                ItemReturner<std::initializer_list<T>>());
    }

}

#endif
<|endoftext|>


<commit_before>// tests the inclusion algorithm for all 2D and 3D elements

#include "FemusInit.hpp"
#include "Marker.hpp"
#include "MultiLevelMesh.hpp"
#include "VTKWriter.hpp"
#include "NonLinearImplicitSystem.hpp"
#include "MyVector.hpp"

using namespace femus;

//2D CASE translation
// double InitalValueU(const std::vector < double >& x) {
//   double time = (x.size() == 4) ? x[3] : 0.;
//   double nHalf = 5.5;
//   double U = 1.;
//   if (time >= nHalf) U  = -1.;
//   return U;
// }
//
// double InitalValueV(const std::vector < double >& x) {
//   return 0.;
// }
//
// double InitalValueW(const std::vector < double >& x) {
//   return 0.;
// }

// 2D CASE rigid rotation
double InitalValueU(const std::vector < double >& x) {
  return -x[1];
}

double InitalValueV(const std::vector < double >& x) {
  return x[0];
}

double InitalValueW(const std::vector < double >& x) {
  return 0.;
}

//3D CASE  rotation
// double InitalValueU(const std::vector < double >& x) {
//   return (-x[1]+x[2])/sqrt(3);
// }
//
// double InitalValueV(const std::vector < double >& x) {
//   return (x[0]-x[2])/sqrt(3);
// }
//
// double InitalValueW(const std::vector < double >& x) {
//   return (x[1]-x[0])/sqrt(3);
// }

// 2D CASE with vorticity
// double pi = acos(-1.);
//
// double InitalValueU(const std::vector < double >& x) {
//   double time = (x.size() == 4) ? x[3] : 0.;
//   return 2. * sin(pi * (x[0] + 0.5)) * sin(pi * (x[0] + 0.5)) * sin(pi * (x[1] + 0.5)) * cos(pi * (x[1] + 0.5)) * cos(time);
// }
//
// double InitalValueV(const std::vector < double >& x) {
//   double time = (x.size() == 4) ? x[3] : 0.;
//   return -2. * sin(pi * (x[1] + 0.5)) * sin(pi * (x[1] + 0.5)) * sin(pi * (x[0] + 0.5)) * cos(pi * (x[0] + 0.5)) * cos(time);
// }
//
// double InitalValueW(const std::vector < double >& x) {
//   double time = (x.size() == 4) ? x[3] : 0.;
//   return 0.;
// }

// 3D CASE with vorticity
// double pi = acos(-1.);
//
// double InitalValueU(const std::vector < double >& x) {
//   double time = (x.size() == 4) ? x[3] : 0.;
//   return
//     2.*(sin(pi * (x[0] + 0.5)) * sin(pi * (x[0] + 0.5)) *
//     ( sin(pi * (x[1] + 0.5)) * cos(pi * (x[1] + 0.5)) - sin(pi * (x[2] + 0.5)) * cos(pi * (x[2] + 0.5)) )
//     )* cos(time);
// }
//
// double InitalValueV(const std::vector < double >& x) {
//   double time = (x.size() == 4) ? x[3] : 0.;
//   return
//     2.*(sin(pi * (x[1] + 0.5)) * sin(pi * (x[1] + 0.5)) *
//     ( sin(pi * (x[2] + 0.5)) * cos(pi * (x[2] + 0.5)) - sin(pi * (x[0] + 0.5)) * cos(pi * (x[0] + 0.5)) )
//     )* cos(time);
// }
//
// double InitalValueW(const std::vector < double >& x) {
//   double time = (x.size() == 4) ? x[3] : 0.;
//   return
//     2.*( sin(pi * (x[2] + 0.5)) * sin(pi * (x[2] + 0.5)) *
//     ( sin(pi * (x[0] + 0.5)) * cos(pi * (x[0] + 0.5)) - sin(pi * (x[1] + 0.5)) * cos(pi * (x[1] + 0.5)) )
//     )* cos(time);
//
//   return 0.;
// }

bool SetRefinementFlag(const std::vector < double >& x, const int& elemgroupnumber, const int& level) {

  bool refine = 0;

  if(elemgroupnumber == 6 && level < 4) refine = 1;
  if(elemgroupnumber == 7 && level < 5) refine = 1;
  if(elemgroupnumber == 8 && level < 6) refine = 1;

  return refine;

}

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

  // init Petsc-MPI communicator
  FemusInit mpinit(argc, args, MPI_COMM_WORLD);

  std::vector < double > x(3, 0); // marker
  MultiLevelMesh mlMsh;
  double scalingFactor = 1.;
   //unsigned numberOfUniformLevels = 3; //for refinement in 3D
  unsigned numberOfUniformLevels = 1;
  unsigned numberOfSelectiveLevels = 0;
  std::vector < std::string > variablesToBePrinted;

  /* element types
  0 = HEX
  1 = TET
  2 = WEDGE
  3 = QUAD
  4 = TRI
   */

  unsigned solType = 2;

  std::cout << " --------------------------------------------------     TEST     --------------------------------------------------" << std::endl;

  //mlMsh.ReadCoarseMesh("./input/prism3D.neu", "seventh", scalingFactor);
  //mlMsh.ReadCoarseMesh("./input/square.neu", "seventh", scalingFactor);
  //mlMsh.ReadCoarseMesh("./input/tri2.neu", "seventh", scalingFactor);
  //mlMsh.ReadCoarseMesh("./input/cubeMixed.neu", "seventh", scalingFactor);
  //mlMsh.ReadCoarseMesh("./input/test3Dbis.neu", "seventh", scalingFactor);
  mlMsh.ReadCoarseMesh("./input/test2Dbis.neu", "seventh", scalingFactor);
  //mlMsh.ReadCoarseMesh("./input/test2D.neu", "seventh", scalingFactor);
  //mlMsh.ReadCoarseMesh("./input/cubeTet.neu", "seventh", scalingFactor);
  mlMsh.RefineMesh(numberOfUniformLevels + numberOfSelectiveLevels, numberOfUniformLevels , SetRefinementFlag);

  unsigned dim = mlMsh.GetDimension();

  MultiLevelSolution mlSol(&mlMsh);
  // add variables to mlSol
  mlSol.AddSolution("U", LAGRANGE, SECOND, 2);
  mlSol.AddSolution("V", LAGRANGE, SECOND, 2);
  if(dim == 3) mlSol.AddSolution("W", LAGRANGE, SECOND, 2);
  mlSol.Initialize("U" , InitalValueU);
  mlSol.Initialize("V" , InitalValueV);
  if(dim == 3) mlSol.Initialize("W", InitalValueW);

//   //Test 1 (QUAD):

//   x[0] = 0.125;
//   x[1] = 0.125;
//   x[2] = -0.25;

  std::cout << " --------------------------------------------------------------------------------------------- " << std::endl;
 // Marker a1Quad(x, VOLUME, mlMsh.GetLevel(0), solType, true);
  //Marker a( x, VOLUME, mlMsh.GetLevel(numberOfUniformLevels + numberOfSelectiveLevels -1) );
  //std::cout << " The coordinates of the marker are " << x[0] << " ," << x[1] << " ," << x[2] << std::endl;
  //std::cout << " The marker type is " <<  a1Quad.GetMarkerType() << std::endl;

  double T = 2 * acos(-1.);
  unsigned n  = 1;

//   std::vector< std::vector < std::vector < double > > > xn(1);
//   xn[0].resize(n + 1);
//   for(unsigned k = 0; k < n; k++) {
//     a1Quad.GetMarkerCoordinates(xn[0][k]);
//     a1Quad.Advection(mlSol.GetLevel(0), 2, T / n);
//   }
//   a1Quad.GetMarkerCoordinates(xn[0][n]);
//   for(unsigned i = 0;  i < xn[0].size(); i++) {
//     for(unsigned d = 0; d < xn[0][i].size(); d++) {
//       //   std::cout << xn[0][i][d] << " ";
//     }
//     // std::cout << std::endl;
//   }
//
//
  variablesToBePrinted.push_back("All");

  VTKWriter vtkIO(&mlSol);
  vtkIO.SetDebugOutput(true);
  vtkIO.Write(DEFAULT_OUTPUTDIR, "biquadratic", variablesToBePrinted);

 // PrintLine(DEFAULT_OUTPUTDIR, xn);

  unsigned pSize = 100;
  std::vector < Marker*> particle(pSize);

//uncomment to do solid body rotation and vortex test
  double pi = acos(-1.);
  for(unsigned j = 0; j < pSize; j++) {
    x[0] = 0. + 0.125 * cos(2.*pi / pSize * j);
    x[1] = .25 + 0.125 * sin(2.*pi / pSize * j);
    x[2] = 0.;
    particle[j] = new Marker(x, VOLUME, mlMsh.GetLevel(numberOfUniformLevels - 1), solType, true);
  }

  //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  //initializing the particles and time for the translation test
//   for(unsigned j = 0; j < pSize; j++) {
//     x[0] = -0.5;
//     x[1] = -0.5 + 0.01 * static_cast<double>(j);
//     x[2] = 0.;
//     particle[j] = new Marker(x, VOLUME, mlMsh.GetLevel(numberOfUniformLevels - 1), solType, true);
//   }
  //BEGIN TESTS PER CAPIRE CHE CASPITA SUCCEDE COL PUNTO j = 58
//   std::vector < double > xTrial(3, 0);
//   particle[58]->GetMarkerCoordinates(xTrial);
//   for(unsigned k=0; k<3; k++){
//     std::cout << "xTrial[" << k << "] = " << xTrial[k] << std::endl;
//   }
//   xTrial[0] = 1.5;
//   xTrial[1] = 1.7;
//   xTrial[2] = 1.;
//   Marker aTrial(xTrial, VOLUME, mlMsh.GetLevel(numberOfUniformLevels - 1), solType, true);
//   xTrial[0] = 15.;
//   xTrial[1] = 15.;
//   xTrial[2] = 0.;
//   aTrial.GetMarkerCoordinates(xTrial);
//
//    for(unsigned k=0; k<3; k++){
//     std::cout << "xTrial[" << k << "] = " << xTrial[k] << std::endl;
//   }
  //END
  //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

  std::vector < std::vector < std::vector < double > > > line(1);
  line[0].resize(pSize + 1);

  for(unsigned j = 0; j < pSize; j++) {
    particle[j]->GetMarkerCoordinates(line[0][j]);
  }
  particle[0]->GetMarkerCoordinates(line[0][pSize]);

  std::vector < std::vector < std::vector < double > > > line0 = line; // saves the initial position
  PrintLine(DEFAULT_OUTPUTDIR, line, false, 0);

  n = 250;

  //comment T for tests that are not translation
  // T = 2. ;
  clock_t start_time = clock();

  // k<=n+1 for translation k<=n for the other tests
  for(unsigned k = 1; k <= n; k++) {
// uncomment for  vortex test
//mlSol.CopySolutionToOldSolution();
//     mlSol.UpdateSolution("U" , InitalValueU, pi * k / n);
//     mlSol.UpdateSolution("V" , InitalValueV, pi * k / n);
//     if(dim == 3) mlSol.UpdateSolution("W" , InitalValueW, pi * k / n);

    //uncomment for vortex test and rigid rotation
          for(unsigned j = 0; j < pSize; j++) {
	particle[j]->Advection(mlSol.GetLevel(numberOfUniformLevels - 1), 4, T / n);
	particle[j]->GetMarkerCoordinates(line[0][j]);
      }
      particle[0]->GetMarkerCoordinates(line[0][pSize]);
      PrintLine(DEFAULT_OUTPUTDIR, line, false, k);
    }

    //uncomment for translation test
//     mlSol.CopySolutionToOldSolution();
//     mlSol.UpdateSolution("U" , InitalValueU, static_cast<double>(k));
//     mlSol.UpdateSolution("V" , InitalValueV, static_cast<double>(k));
//     if(dim == 3) mlSol.UpdateSolution("W" , InitalValueW, static_cast<double>(k));
//
//     if(k != 6){
//       for(unsigned j = 0; j < pSize; j++) {
// 	particle[j]->Advection(mlSol.GetLevel(numberOfUniformLevels - 1), 4, T / n);
// 	particle[j]->GetMarkerCoordinates(line[0][j]);
//       }
//       particle[0]->GetMarkerCoordinates(line[0][pSize]);
//       PrintLine(DEFAULT_OUTPUTDIR, line, false, k);
//     }
//  }

  std::cout << std::endl << " RANNA in: " << std::setw(11) << std::setprecision(6) << std::fixed
            << static_cast<double>((clock() - start_time)) / CLOCKS_PER_SEC << " s" << std::endl;

  //computing the geometric error
  double error = 0.;
  for(unsigned j = 0; j < pSize + 1; j++) {
    double tempError = 0.;
    for(unsigned i = 0; i < dim; i++) {
      tempError += (line0[0][j][i] - line[0][j][i]) * (line0[0][j][i] - line[0][j][i]);
    }
    error += sqrt(tempError);
  }

  error = error / pSize;

  std::cout << " ERROR = " << std::setprecision(15) << error << std::endl;

  for(unsigned j = 0; j < pSize; j++) {
    delete particle[j];
  }

  return 0;
}

<commit_msg>testing the 3D rotation<commit_after>// tests the inclusion algorithm for all 2D and 3D elements

#include "FemusInit.hpp"
#include "Marker.hpp"
#include "MultiLevelMesh.hpp"
#include "VTKWriter.hpp"
#include "NonLinearImplicitSystem.hpp"
#include "MyVector.hpp"

using namespace femus;

//2D CASE translation
// double InitalValueU(const std::vector < double >& x) {
//   double time = (x.size() == 4) ? x[3] : 0.;
//   double nHalf = 5.5;
//   double U = 1.;
//   if (time >= nHalf) U  = -1.;
//   return U;
// }
//
// double InitalValueV(const std::vector < double >& x) {
//   return 0.;
// }
//
// double InitalValueW(const std::vector < double >& x) {
//   return 0.;
// }

// 2D CASE rigid rotation
// double InitalValueU(const std::vector < double >& x) {
//   return -x[1];
// }
//
// double InitalValueV(const std::vector < double >& x) {
//   return x[0];
// }
//
// double InitalValueW(const std::vector < double >& x) {
//   return 0.;
// }

//3D CASE  rotation
double InitalValueU(const std::vector < double >& x) {
  return (-x[1]+x[2])/sqrt(3);
}

double InitalValueV(const std::vector < double >& x) {
  return (x[0]-x[2])/sqrt(3);
}

double InitalValueW(const std::vector < double >& x) {
  return (x[1]-x[0])/sqrt(3);
}

// 2D CASE with vorticity
// double pi = acos(-1.);
//
// double InitalValueU(const std::vector < double >& x) {
//   double time = (x.size() == 4) ? x[3] : 0.;
//   return 2. * sin(pi * (x[0] + 0.5)) * sin(pi * (x[0] + 0.5)) * sin(pi * (x[1] + 0.5)) * cos(pi * (x[1] + 0.5)) * cos(time);
// }
//
// double InitalValueV(const std::vector < double >& x) {
//   double time = (x.size() == 4) ? x[3] : 0.;
//   return -2. * sin(pi * (x[1] + 0.5)) * sin(pi * (x[1] + 0.5)) * sin(pi * (x[0] + 0.5)) * cos(pi * (x[0] + 0.5)) * cos(time);
// }
//
// double InitalValueW(const std::vector < double >& x) {
//   double time = (x.size() == 4) ? x[3] : 0.;
//   return 0.;
// }

// 3D CASE with vorticity
// double pi = acos(-1.);
//
// double InitalValueU(const std::vector < double >& x) {
//   double time = (x.size() == 4) ? x[3] : 0.;
//   return
//     2.*(sin(pi * (x[0] + 0.5)) * sin(pi * (x[0] + 0.5)) *
//     ( sin(pi * (x[1] + 0.5)) * cos(pi * (x[1] + 0.5)) - sin(pi * (x[2] + 0.5)) * cos(pi * (x[2] + 0.5)) )
//     )* cos(time);
// }
//
// double InitalValueV(const std::vector < double >& x) {
//   double time = (x.size() == 4) ? x[3] : 0.;
//   return
//     2.*(sin(pi * (x[1] + 0.5)) * sin(pi * (x[1] + 0.5)) *
//     ( sin(pi * (x[2] + 0.5)) * cos(pi * (x[2] + 0.5)) - sin(pi * (x[0] + 0.5)) * cos(pi * (x[0] + 0.5)) )
//     )* cos(time);
// }
//
// double InitalValueW(const std::vector < double >& x) {
//   double time = (x.size() == 4) ? x[3] : 0.;
//   return
//     2.*( sin(pi * (x[2] + 0.5)) * sin(pi * (x[2] + 0.5)) *
//     ( sin(pi * (x[0] + 0.5)) * cos(pi * (x[0] + 0.5)) - sin(pi * (x[1] + 0.5)) * cos(pi * (x[1] + 0.5)) )
//     )* cos(time);
//
//   return 0.;
// }

bool SetRefinementFlag(const std::vector < double >& x, const int& elemgroupnumber, const int& level) {

  bool refine = 0;

  if(elemgroupnumber == 6 && level < 4) refine = 1;
  if(elemgroupnumber == 7 && level < 5) refine = 1;
  if(elemgroupnumber == 8 && level < 6) refine = 1;

  return refine;

}

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

  // init Petsc-MPI communicator
  FemusInit mpinit(argc, args, MPI_COMM_WORLD);

  std::vector < double > x(3, 0); // marker
  MultiLevelMesh mlMsh;
  double scalingFactor = 1.;
  unsigned numberOfUniformLevels = 3; //for refinement in 3D
  //unsigned numberOfUniformLevels = 1;
  unsigned numberOfSelectiveLevels = 0;
  std::vector < std::string > variablesToBePrinted;

  /* element types
  0 = HEX
  1 = TET
  2 = WEDGE
  3 = QUAD
  4 = TRI
   */

  unsigned solType = 2;

  std::cout << " --------------------------------------------------     TEST     --------------------------------------------------" << std::endl;

  //mlMsh.ReadCoarseMesh("./input/prism3D.neu", "seventh", scalingFactor);
  //mlMsh.ReadCoarseMesh("./input/square.neu", "seventh", scalingFactor);
  //mlMsh.ReadCoarseMesh("./input/tri2.neu", "seventh", scalingFactor);
  //mlMsh.ReadCoarseMesh("./input/cubeMixed.neu", "seventh", scalingFactor);
  mlMsh.ReadCoarseMesh("./input/test3Dbis.neu", "seventh", scalingFactor);
  //mlMsh.ReadCoarseMesh("./input/test2Dbis.neu", "seventh", scalingFactor);
  //mlMsh.ReadCoarseMesh("./input/test2D.neu", "seventh", scalingFactor);
  //mlMsh.ReadCoarseMesh("./input/cubeTet.neu", "seventh", scalingFactor);
  mlMsh.RefineMesh(numberOfUniformLevels + numberOfSelectiveLevels, numberOfUniformLevels , SetRefinementFlag);

  unsigned dim = mlMsh.GetDimension();

  MultiLevelSolution mlSol(&mlMsh);
  // add variables to mlSol
  mlSol.AddSolution("U", LAGRANGE, SECOND, 2);
  mlSol.AddSolution("V", LAGRANGE, SECOND, 2);
  if(dim == 3) mlSol.AddSolution("W", LAGRANGE, SECOND, 2);
  mlSol.Initialize("U" , InitalValueU);
  mlSol.Initialize("V" , InitalValueV);
  if(dim == 3) mlSol.Initialize("W", InitalValueW);

//   //Test 1 (QUAD):

//   x[0] = 0.125;
//   x[1] = 0.125;
//   x[2] = -0.25;

  std::cout << " --------------------------------------------------------------------------------------------- " << std::endl;
 // Marker a1Quad(x, VOLUME, mlMsh.GetLevel(0), solType, true);
  //Marker a( x, VOLUME, mlMsh.GetLevel(numberOfUniformLevels + numberOfSelectiveLevels -1) );
  //std::cout << " The coordinates of the marker are " << x[0] << " ," << x[1] << " ," << x[2] << std::endl;
  //std::cout << " The marker type is " <<  a1Quad.GetMarkerType() << std::endl;

  double T = 2 * acos(-1.);
  unsigned n  = 1;

//   std::vector< std::vector < std::vector < double > > > xn(1);
//   xn[0].resize(n + 1);
//   for(unsigned k = 0; k < n; k++) {
//     a1Quad.GetMarkerCoordinates(xn[0][k]);
//     a1Quad.Advection(mlSol.GetLevel(0), 2, T / n);
//   }
//   a1Quad.GetMarkerCoordinates(xn[0][n]);
//   for(unsigned i = 0;  i < xn[0].size(); i++) {
//     for(unsigned d = 0; d < xn[0][i].size(); d++) {
//       //   std::cout << xn[0][i][d] << " ";
//     }
//     // std::cout << std::endl;
//   }
//
//
  variablesToBePrinted.push_back("All");

  VTKWriter vtkIO(&mlSol);
  vtkIO.SetDebugOutput(true);
  vtkIO.Write(DEFAULT_OUTPUTDIR, "biquadratic", variablesToBePrinted);

 // PrintLine(DEFAULT_OUTPUTDIR, xn);

  unsigned pSize = 100;
  std::vector < Marker*> particle(pSize);

//uncomment to do solid body rotation and vortex test
  double pi = acos(-1.);
  for(unsigned j = 0; j < pSize; j++) {
    x[0] = 0. + 0.125 * cos(2.*pi / pSize * j);
    x[1] = .25 + 0.125 * sin(2.*pi / pSize * j);
    x[2] = 0.;
    particle[j] = new Marker(x, VOLUME, mlMsh.GetLevel(numberOfUniformLevels - 1), solType, true);
  }

  //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  //initializing the particles and time for the translation test
//   for(unsigned j = 0; j < pSize; j++) {
//     x[0] = -0.5;
//     x[1] = -0.5 + 0.01 * static_cast<double>(j);
//     x[2] = 0.;
//     particle[j] = new Marker(x, VOLUME, mlMsh.GetLevel(numberOfUniformLevels - 1), solType, true);
//   }
  //BEGIN TESTS PER CAPIRE CHE CASPITA SUCCEDE COL PUNTO j = 58
//   std::vector < double > xTrial(3, 0);
//   particle[58]->GetMarkerCoordinates(xTrial);
//   for(unsigned k=0; k<3; k++){
//     std::cout << "xTrial[" << k << "] = " << xTrial[k] << std::endl;
//   }
//   xTrial[0] = 1.5;
//   xTrial[1] = 1.7;
//   xTrial[2] = 1.;
//   Marker aTrial(xTrial, VOLUME, mlMsh.GetLevel(numberOfUniformLevels - 1), solType, true);
//   xTrial[0] = 15.;
//   xTrial[1] = 15.;
//   xTrial[2] = 0.;
//   aTrial.GetMarkerCoordinates(xTrial);
//
//    for(unsigned k=0; k<3; k++){
//     std::cout << "xTrial[" << k << "] = " << xTrial[k] << std::endl;
//   }
  //END
  //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

  std::vector < std::vector < std::vector < double > > > line(1);
  line[0].resize(pSize + 1);

  for(unsigned j = 0; j < pSize; j++) {
    particle[j]->GetMarkerCoordinates(line[0][j]);
  }
  particle[0]->GetMarkerCoordinates(line[0][pSize]);

  std::vector < std::vector < std::vector < double > > > line0 = line; // saves the initial position
  PrintLine(DEFAULT_OUTPUTDIR, line, false, 0);

  n = 10;

  //comment T for tests that are not translation
  // T = 2. ;
  clock_t start_time = clock();

  // k<=n+1 for translation k<=n for the other tests
  for(unsigned k = 1; k <= n; k++) {
// uncomment for  vortex test
//mlSol.CopySolutionToOldSolution();
//     mlSol.UpdateSolution("U" , InitalValueU, pi * k / n);
//     mlSol.UpdateSolution("V" , InitalValueV, pi * k / n);
//     if(dim == 3) mlSol.UpdateSolution("W" , InitalValueW, pi * k / n);

    //uncomment for vortex test and rigid rotation
          for(unsigned j = 0; j < pSize; j++) {
	particle[j]->Advection(mlSol.GetLevel(numberOfUniformLevels - 1), 4, T / n);
	particle[j]->GetMarkerCoordinates(line[0][j]);
      }
      particle[0]->GetMarkerCoordinates(line[0][pSize]);
      PrintLine(DEFAULT_OUTPUTDIR, line, false, k);
    }

    //uncomment for translation test
//     mlSol.CopySolutionToOldSolution();
//     mlSol.UpdateSolution("U" , InitalValueU, static_cast<double>(k));
//     mlSol.UpdateSolution("V" , InitalValueV, static_cast<double>(k));
//     if(dim == 3) mlSol.UpdateSolution("W" , InitalValueW, static_cast<double>(k));
//
//     if(k != 6){
//       for(unsigned j = 0; j < pSize; j++) {
// 	particle[j]->Advection(mlSol.GetLevel(numberOfUniformLevels - 1), 4, T / n);
// 	particle[j]->GetMarkerCoordinates(line[0][j]);
//       }
//       particle[0]->GetMarkerCoordinates(line[0][pSize]);
//       PrintLine(DEFAULT_OUTPUTDIR, line, false, k);
//     }
//  }

  std::cout << std::endl << " RANNA in: " << std::setw(11) << std::setprecision(6) << std::fixed
            << static_cast<double>((clock() - start_time)) / CLOCKS_PER_SEC << " s" << std::endl;

  //computing the geometric error
  double error = 0.;
  for(unsigned j = 0; j < pSize + 1; j++) {
    double tempError = 0.;
    for(unsigned i = 0; i < dim; i++) {
      tempError += (line0[0][j][i] - line[0][j][i]) * (line0[0][j][i] - line[0][j][i]);
    }
    error += sqrt(tempError);
  }

  error = error / pSize;

  std::cout << " ERROR = " << std::setprecision(15) << error << std::endl;

  for(unsigned j = 0; j < pSize; j++) {
    delete particle[j];
  }

  return 0;
}

<|endoftext|>