new Operator_Base class

- This class is meant as an abstract base for any time-domain and rect-grid numerical solver.
- All processing methods should only use this base class

Signed-off-by: Thorsten Liebig <Thorsten.Liebig@gmx.de>
pull/1/head
Thorsten Liebig 2010-12-06 09:59:42 +01:00
parent 32cbdc5d0b
commit 16263e8f9a
24 changed files with 201 additions and 67 deletions

53
Common/operator_base.cpp Normal file
View File

@ -0,0 +1,53 @@
/*
* Copyright (C) 2010 Thorsten Liebig (Thorsten.Liebig@gmx.de)
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "operator_base.h"
Operator_Base::Operator_Base()
{
Init();
m_MeshType = Processing::CARTESIAN_MESH;
}
Operator_Base::~Operator_Base()
{
}
std::string Operator_Base::GetDirName(int ny) const
{
if (ny==0) return "x";
if (ny==1) return "y";
if (ny==2) return "z";
return "";
}
void Operator_Base::Init()
{
dT = 0;
for (int n=0;n<3;++n)
discLines[n]=NULL;
for (int n=0;n<6;++n)
m_BC[n]=0;
}
void Operator_Base::Reset()
{
for (int n=0;n<3;++n)
delete[] discLines[n];
Init();
}

93
Common/operator_base.h Normal file
View File

@ -0,0 +1,93 @@
/*
* Copyright (C) 2010 Thorsten Liebig (Thorsten.Liebig@gmx.de)
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef OPERATOR_BASE_H
#define OPERATOR_BASE_H
#include "tools/global.h"
#include "FDTD/processing.h"
#include "string"
class Operator_Base
{
public:
//! Get the timestep used by this operator
double GetTimestep() const {return dT;};
//! Get the number of cells or nodes defined by this operator
virtual double GetNumberCells() const {return 0;}
//! Get the number of timesteps satisfying the nyquist condition (may depend on the excitation)
unsigned int GetNumberOfNyquistTimesteps() const {return 0;}
//! Returns the number of lines as needed for post-processing etc. (for the engine, use GetOriginalNumLines())
virtual unsigned int GetNumberOfLines(int ny) const {return numLines[ny];}
//! Get the name for the given direction: 0 -> x, 1 -> y, 2 -> z
virtual std::string GetDirName(int ny) const;
//! Get the grid drawing unit in m
virtual double GetGridDelta() const {return 0;}
//! Get the mesh delta times the grid delta for a 3D position (unit is meter)
virtual double GetMeshDelta(int n, const unsigned int* pos, bool dualMesh=false) const {UNUSED(n);UNUSED(pos);UNUSED(dualMesh);return 0.0;}
//! Get the disc line in \a n direction (in drawing units)
virtual double GetDiscLine(int n, unsigned int pos, bool dualMesh=false) const {UNUSED(n);UNUSED(pos);UNUSED(dualMesh);return 0.0;}
//! Get the node width for a given direction \a n and a given mesh position \a pos
virtual double GetNodeWidth(int ny, const unsigned int pos[3], bool dualMesh = false) const {UNUSED(ny);UNUSED(pos);UNUSED(dualMesh);return 0.0;}
//! Get the node area for a given direction \a n and a given mesh position \a pos
virtual double GetNodeArea(int ny, const unsigned int pos[3], bool dualMesh = false) const {UNUSED(ny);UNUSED(pos);UNUSED(dualMesh);return 0.0;}
//! Get the length of an FDTD edge (unit is meter).
virtual double GetEdgeLength(int ny, const unsigned int pos[3], bool dualMesh = false) const {UNUSED(ny);UNUSED(pos);UNUSED(dualMesh);return 0.0;}
//! Get the area around an edge for a given direction \a n and a given mesh posisition \a pos
/*!
This will return the area around an edge with a given direction, measured at the middle of the edge.
In a cartesian mesh this is equal to the NodeArea, may be different in other coordinate systems.
*/
virtual double GetEdgeArea(int ny, const unsigned int pos[3], bool dualMesh = false) const {UNUSED(ny);UNUSED(pos);UNUSED(dualMesh);return 0.0;}
//! Snap the given coodinates to mesh indices
virtual bool SnapToMesh(double* coord, unsigned int* uicoord, bool lower=false, bool* inside=NULL) {UNUSED(coord);UNUSED(uicoord);UNUSED(lower);UNUSED(inside);return false;};
//! Set the boundary conditions
virtual void SetBoundaryCondition(int* BCs) {for (int n=0;n<6;++n) m_BC[n]=BCs[n];}
protected:
Operator_Base();
virtual ~Operator_Base();
virtual void Init();
virtual void Reset();
//! boundary conditions
int m_BC[6];
//! The operator timestep
double dT;
Processing::MeshType m_MeshType;
unsigned int numLines[3];
double* discLines[3];
double gridDelta;
};
#endif // OPERATOR_BASE_H

View File

@ -1,5 +1,6 @@
readme for openEMS/Commen readme for openEMS/Commen
- This folder contains all classes common for all numerical solver included in openEMS (currently only FDTD) - This folder contains all classes common for all numerical solver included in openEMS (currently only FDTD)
- Operator-Base class
- Engine-Interface classes - Engine-Interface classes
- Commen processing classes - Commen processing classes

View File

@ -31,11 +31,9 @@ Operator* Operator::New()
return op; return op;
} }
Operator::Operator() Operator::Operator() : Operator_Base()
{ {
m_MeshType = ProcessFields::CARTESIAN_MESH;
Exc = 0; Exc = 0;
dT = 0;
m_InvaildTimestep = false; m_InvaildTimestep = false;
} }
@ -55,14 +53,14 @@ Engine* Operator::CreateEngine() const
void Operator::Init() void Operator::Init()
{ {
Operator_Base::Init();
CSX = NULL; CSX = NULL;
vv=NULL; vv=NULL;
vi=NULL; vi=NULL;
iv=NULL; iv=NULL;
ii=NULL; ii=NULL;
for (int n=0;n<3;++n)
discLines[n]=NULL;
MainOp=NULL; MainOp=NULL;
DualOp=NULL; DualOp=NULL;
@ -75,11 +73,7 @@ void Operator::Init()
EC_R[n]=NULL; EC_R[n]=NULL;
} }
for (int n=0;n<6;++n)
m_BC[n]=0;
Exc = 0; Exc = 0;
dT = 0;
} }
void Operator::Reset() void Operator::Reset()
@ -88,8 +82,6 @@ void Operator::Reset()
Delete_N_3DArray(vi,numLines); Delete_N_3DArray(vi,numLines);
Delete_N_3DArray(iv,numLines); Delete_N_3DArray(iv,numLines);
Delete_N_3DArray(ii,numLines); Delete_N_3DArray(ii,numLines);
for (int n=0;n<3;++n)
delete[] discLines[n];
delete MainOp; delete MainOp;
delete DualOp; delete DualOp;
for (int n=0;n<3;++n) for (int n=0;n<3;++n)
@ -102,15 +94,7 @@ void Operator::Reset()
delete Exc; delete Exc;
Init(); Operator_Base::Reset();
}
string Operator::GetDirName(int ny) const
{
if (ny==0) return "x";
if (ny==1) return "y";
if (ny==2) return "z";
return "";
} }
double Operator::GetMeshDelta(int n, const unsigned int* pos, bool dualMesh) const double Operator::GetMeshDelta(int n, const unsigned int* pos, bool dualMesh) const

View File

@ -22,13 +22,14 @@
#include "tools/AdrOp.h" #include "tools/AdrOp.h"
#include "tools/constants.h" #include "tools/constants.h"
#include "excitation.h" #include "excitation.h"
#include "Common/operator_base.h"
class Operator_Extension; class Operator_Extension;
class Engine; class Engine;
class TiXmlElement; class TiXmlElement;
//! Abstract base-class for the FDTD-operator //! Abstract base-class for the FDTD-operator
class Operator class Operator : public Operator_Base
{ {
friend class Engine; friend class Engine;
friend class Operator_Ext_LorentzMaterial; //we need to find a way around this... friend class Operator_Extension only would be nice friend class Operator_Ext_LorentzMaterial; //we need to find a way around this... friend class Operator_Extension only would be nice
@ -73,27 +74,22 @@ public:
inline virtual void SetII( unsigned int n, unsigned int x, unsigned int y, unsigned int z, FDTD_FLOAT value ) { ii[n][x][y][z] = value; } inline virtual void SetII( unsigned int n, unsigned int x, unsigned int y, unsigned int z, FDTD_FLOAT value ) { ii[n][x][y][z] = value; }
inline virtual void SetIV( unsigned int n, unsigned int x, unsigned int y, unsigned int z, FDTD_FLOAT value ) { iv[n][x][y][z] = value; } inline virtual void SetIV( unsigned int n, unsigned int x, unsigned int y, unsigned int z, FDTD_FLOAT value ) { iv[n][x][y][z] = value; }
virtual void SetBoundaryCondition(int* BCs) {for (int n=0;n<6;++n) m_BC[n]=BCs[n];}
virtual void ApplyElectricBC(bool* dirs); //applied by default to all boundaries virtual void ApplyElectricBC(bool* dirs); //applied by default to all boundaries
virtual void ApplyMagneticBC(bool* dirs); virtual void ApplyMagneticBC(bool* dirs);
//! Set a forced timestep to use by the operator //! Set a forced timestep to use by the operator
virtual void SetTimestep(double ts) {dT = ts;} virtual void SetTimestep(double ts) {dT = ts;}
double GetTimestep() const {return dT;};
bool GetTimestepValid() const {return !m_InvaildTimestep;} bool GetTimestepValid() const {return !m_InvaildTimestep;}
virtual double GetNumberCells() const; virtual double GetNumberCells() const;
//! Returns the number of lines as needed for post-processing etc. (for the engine, use GetOriginalNumLines()) unsigned int GetNumberOfNyquistTimesteps() const {return Exc->GetNyquistNum();}
virtual unsigned int GetNumberOfLines(int ny) const {return numLines[ny];}
//! Returns the number of lines as needed for the engine etc. (for post-processing etc, use GetOriginalNumLines()) //! Returns the number of lines as needed for the engine etc. (for post-processing etc, use GetNumLines())
virtual unsigned int GetOriginalNumLines(int ny) const {return numLines[ny];} virtual unsigned int GetOriginalNumLines(int ny) const {return numLines[ny];}
virtual void ShowStat() const; virtual void ShowStat() const;
virtual void ShowExtStat() const; virtual void ShowExtStat() const;
//! Get the name for the given direction: 0 -> x, 1 -> y, 2 -> z
virtual string GetDirName(int ny) const;
virtual double GetGridDelta() const {return gridDelta;} virtual double GetGridDelta() const {return gridDelta;}
//! Get the mesh delta times the grid delta for a 3D position (unit is meter) //! Get the mesh delta times the grid delta for a 3D position (unit is meter)
virtual double GetMeshDelta(int n, const unsigned int* pos, bool dualMesh=false) const; virtual double GetMeshDelta(int n, const unsigned int* pos, bool dualMesh=false) const;
@ -141,8 +137,6 @@ protected:
ContinuousStructure* CSX; ContinuousStructure* CSX;
int m_BC[6];
//! Calculate the field excitations. //! Calculate the field excitations.
virtual bool CalcFieldExcitation(); virtual bool CalcFieldExcitation();
@ -158,7 +152,6 @@ protected:
//Calc timestep only internal use //Calc timestep only internal use
virtual double CalcTimestep(); virtual double CalcTimestep();
double dT; //FDTD timestep!
double opt_dT; double opt_dT;
bool m_InvaildTimestep; bool m_InvaildTimestep;
string m_Used_TS_Name; string m_Used_TS_Name;
@ -177,10 +170,6 @@ protected:
double* EC_L[3]; double* EC_L[3];
double* EC_R[3]; double* EC_R[3];
int m_MeshType;
unsigned int numLines[3];
double* discLines[3];
double gridDelta;
AdrOp* MainOp; AdrOp* MainOp;
AdrOp* DualOp; AdrOp* DualOp;

View File

@ -19,7 +19,7 @@
#include "time.h" #include "time.h"
#include "process_efield.h" #include "process_efield.h"
ProcessEField::ProcessEField(Operator* op, Engine* eng) : Processing(op) ProcessEField::ProcessEField(Operator_Base* op, Engine* eng) : Processing(op)
{ {
Eng = eng; Eng = eng;
} }

View File

@ -19,6 +19,7 @@
#define PROCESS_EFIELD_H #define PROCESS_EFIELD_H
#include "processing.h" #include "processing.h"
#include "engine.h"
/*! \brief Process E-field at a point /*! \brief Process E-field at a point
@ -28,7 +29,7 @@
class ProcessEField : public Processing class ProcessEField : public Processing
{ {
public: public:
ProcessEField(Operator* op, Engine* eng); ProcessEField(Operator_Base* op, Engine* eng);
virtual ~ProcessEField(); virtual ~ProcessEField();
virtual void InitProcess(); virtual void InitProcess();

View File

@ -19,7 +19,7 @@
#include "tools/global.h" #include "tools/global.h"
#include "process_hfield.h" #include "process_hfield.h"
ProcessHField::ProcessHField(Operator* op, Engine* eng) : ProcessEField(op, eng) ProcessHField::ProcessHField(Operator_Base* op, Engine* eng) : ProcessEField(op, eng)
{ {
} }

View File

@ -28,7 +28,7 @@
class ProcessHField : public ProcessEField class ProcessHField : public ProcessEField
{ {
public: public:
ProcessHField(Operator* op, Engine* eng); ProcessHField(Operator_Base* op, Engine* eng);
virtual ~ProcessHField(); virtual ~ProcessHField();
virtual void InitProcess(); virtual void InitProcess();

View File

@ -20,7 +20,7 @@
#include "engine_interface_fdtd.h" #include "engine_interface_fdtd.h"
#include <iomanip> #include <iomanip>
ProcessCurrent::ProcessCurrent(Operator* op) : ProcessIntegral(op) ProcessCurrent::ProcessCurrent(Operator_Base* op) : ProcessIntegral(op)
{ {
m_TimeShift = op->GetTimestep()/2.0; m_TimeShift = op->GetTimestep()/2.0;
m_dualMesh = true; m_dualMesh = true;

View File

@ -23,7 +23,7 @@
class ProcessCurrent : public ProcessIntegral class ProcessCurrent : public ProcessIntegral
{ {
public: public:
ProcessCurrent(Operator* op); ProcessCurrent(Operator_Base* op);
virtual ~ProcessCurrent(); virtual ~ProcessCurrent();
//! Integrate currents flowing through an area //! Integrate currents flowing through an area

View File

@ -21,7 +21,7 @@
#include "processfields.h" #include "processfields.h"
#include "engine_interface_fdtd.h" #include "engine_interface_fdtd.h"
ProcessFields::ProcessFields(Operator* op) : Processing(op) ProcessFields::ProcessFields(Operator_Base* op) : Processing(op)
{ {
m_DumpType = E_FIELD_DUMP; m_DumpType = E_FIELD_DUMP;
// vtk-file is default // vtk-file is default

View File

@ -26,7 +26,7 @@
class ProcessFields : public Processing class ProcessFields : public Processing
{ {
public: public:
ProcessFields(Operator* op); ProcessFields(Operator_Base* op);
virtual ~ProcessFields(); virtual ~ProcessFields();
enum FileType { VTK_FILETYPE, HDF5_FILETYPE}; enum FileType { VTK_FILETYPE, HDF5_FILETYPE};

View File

@ -16,11 +16,12 @@
*/ */
#include "processfields_td.h" #include "processfields_td.h"
#include "Common/operator_base.h"
#include <iomanip> #include <iomanip>
#include <sstream> #include <sstream>
#include <string> #include <string>
ProcessFieldsTD::ProcessFieldsTD(Operator* op) : ProcessFields(op) ProcessFieldsTD::ProcessFieldsTD(Operator_Base* op) : ProcessFields(op)
{ {
pad_length = 8; pad_length = 8;
} }

View File

@ -23,7 +23,7 @@
class ProcessFieldsTD : public ProcessFields class ProcessFieldsTD : public ProcessFields
{ {
public: public:
ProcessFieldsTD(Operator* op); ProcessFieldsTD(Operator_Base* op);
virtual ~ProcessFieldsTD(); virtual ~ProcessFieldsTD();
virtual int Process(); virtual int Process();

View File

@ -17,11 +17,13 @@
#include "tools/global.h" #include "tools/global.h"
#include "tools/useful.h" #include "tools/useful.h"
#include "Common/operator_base.h"
#include <algorithm>
#include "processing.h" #include "processing.h"
#include "time.h" #include "time.h"
#include <climits> #include <climits>
Processing::Processing(Operator* op) Processing::Processing(Operator_Base* op)
{ {
Op=op; Op=op;
Enabled = true; Enabled = true;
@ -126,13 +128,13 @@ void Processing::AddFrequency(double freq)
cerr << "Processing::AddFrequency: Requested frequency " << freq << " is too high for the current timestep used... skipping..." << endl; cerr << "Processing::AddFrequency: Requested frequency " << freq << " is too high for the current timestep used... skipping..." << endl;
return; return;
} }
else if (nyquistTS<Op->Exc->GetNyquistNum()) else if (nyquistTS<Op->GetNumberOfNyquistTimesteps())
{ {
cerr << "Processing::AddFrequency: Warning: Requested frequency " << freq << " is higher than maximum excited frequency..." << endl; cerr << "Processing::AddFrequency: Warning: Requested frequency " << freq << " is higher than maximum excited frequency..." << endl;
} }
if (m_FD_Interval==0) if (m_FD_Interval==0)
m_FD_Interval = Op->Exc->GetNyquistNum(); m_FD_Interval = Op->GetNumberOfNyquistTimesteps();
if (m_FD_Interval>nyquistTS) if (m_FD_Interval>nyquistTS)
m_FD_Interval = nyquistTS; m_FD_Interval = nyquistTS;

View File

@ -25,22 +25,29 @@ typedef std::complex<double> double_complex;
#include <iostream> #include <iostream>
#include <fstream> #include <fstream>
#include <cmath> #include <cmath>
#include "Common/engine_interface_base.h" #include <stdio.h>
#include "operator.h" #include <stdlib.h>
#include "engine.h" #include <iostream>
#include <string>
#include <vector>
#include "Common/engine_interface_base.h"
class Operator_Base;
using namespace std;
class Processing class Processing
{ {
public: public:
Processing(Operator* op); Processing(Operator_Base* op);
virtual ~Processing(); virtual ~Processing();
enum MeshType { CARTESIAN_MESH, CYLINDRICAL_MESH};
//! Set the interface to the engine. Each processing needs its own engine interface. This class will take ownership and cleanup the interface on deletion! //! Set the interface to the engine. Each processing needs its own engine interface. This class will take ownership and cleanup the interface on deletion!
void SetEngineInterface(Engine_Interface_Base* eng_if); void SetEngineInterface(Engine_Interface_Base* eng_if);
enum MeshType { CARTESIAN_MESH, CYLINDRICAL_MESH};
virtual void SetName(string val) {m_Name=val;} virtual void SetName(string val) {m_Name=val;}
virtual void InitProcess() {}; virtual void InitProcess() {};
@ -84,7 +91,7 @@ public:
protected: protected:
Engine_Interface_Base* m_Eng_Interface; Engine_Interface_Base* m_Eng_Interface;
Operator* Op; Operator_Base* Op;
MeshType m_Mesh_Type; MeshType m_Mesh_Type;
unsigned int m_precision; unsigned int m_precision;

View File

@ -18,7 +18,7 @@
#include "processintegral.h" #include "processintegral.h"
#include <iomanip> #include <iomanip>
ProcessIntegral::ProcessIntegral(Operator* op) : Processing(op) ProcessIntegral::ProcessIntegral(Operator_Base* op) : Processing(op)
{ {
m_TimeShift = 0.0; m_TimeShift = 0.0;
m_Results=NULL; m_Results=NULL;

View File

@ -51,12 +51,12 @@ public:
virtual int Process(); virtual int Process();
protected: protected:
ProcessIntegral(Operator* op); ProcessIntegral(Operator_Base* op);
//! timeshift to be used in TD and FD data, e.g. 0.5*dT in case of current based parameter //! timeshift to be used in TD and FD data, e.g. 0.5*dT in case of current based parameter
double m_TimeShift; double m_TimeShift;
vector<FDTD_FLOAT> TD_Values; vector<double> TD_Values;
vector<double_complex> FD_Values; vector<double_complex> FD_Values;
double *m_Results; double *m_Results;

View File

@ -17,9 +17,10 @@
#include "processmodematch.h" #include "processmodematch.h"
#include "CSFunctionParser.h" #include "CSFunctionParser.h"
#include "Common/operator_base.h"
#include "tools/array_ops.h" #include "tools/array_ops.h"
ProcessModeMatch::ProcessModeMatch(Operator* op) : ProcessIntegral(op) ProcessModeMatch::ProcessModeMatch(Operator_Base* op) : ProcessIntegral(op)
{ {
for (int n=0;n<2;++n) for (int n=0;n<2;++n)
{ {

View File

@ -25,7 +25,7 @@ class CSFunctionParser;
class ProcessModeMatch : public ProcessIntegral class ProcessModeMatch : public ProcessIntegral
{ {
public: public:
ProcessModeMatch(Operator* op); ProcessModeMatch(Operator_Base* op);
virtual ~ProcessModeMatch(); virtual ~ProcessModeMatch();
virtual void InitProcess(); virtual void InitProcess();

View File

@ -18,7 +18,7 @@
#include "processvoltage.h" #include "processvoltage.h"
#include <iomanip> #include <iomanip>
ProcessVoltage::ProcessVoltage(Operator* op) : ProcessIntegral(op) ProcessVoltage::ProcessVoltage(Operator_Base* op) : ProcessIntegral(op)
{ {
} }

View File

@ -24,7 +24,7 @@
class ProcessVoltage : public ProcessIntegral class ProcessVoltage : public ProcessIntegral
{ {
public: public:
ProcessVoltage(Operator* op); ProcessVoltage(Operator_Base* op);
virtual ~ProcessVoltage(); virtual ~ProcessVoltage();
virtual double CalcIntegral(); virtual double CalcIntegral();

View File

@ -86,9 +86,10 @@ SOURCES += main.cpp \
FDTD/engine_cylindermultigrid.cpp \ FDTD/engine_cylindermultigrid.cpp \
FDTD/engine_ext_cylindermultigrid.cpp \ FDTD/engine_ext_cylindermultigrid.cpp \
FDTD/operator_ext_upml.cpp \ FDTD/operator_ext_upml.cpp \
FDTD/engine_ext_upml.cpp \ FDTD/engine_ext_upml.cpp \
Common/engine_interface_base.cpp \ Common/engine_interface_base.cpp \
FDTD/engine_interface_fdtd.cpp FDTD/engine_interface_fdtd.cpp \
Common/operator_base.cpp
HEADERS += tools/ErrorMsg.h \ HEADERS += tools/ErrorMsg.h \
tools/AdrOp.h \ tools/AdrOp.h \
tools/constants.h \ tools/constants.h \
@ -132,9 +133,10 @@ HEADERS += tools/ErrorMsg.h \
FDTD/engine_ext_cylindermultigrid.h \ FDTD/engine_ext_cylindermultigrid.h \
tools/aligned_allocator.h \ tools/aligned_allocator.h \
FDTD/operator_ext_upml.h \ FDTD/operator_ext_upml.h \
FDTD/engine_ext_upml.h \ FDTD/engine_ext_upml.h \
Common/engine_interface_base.h \ Common/engine_interface_base.h \
FDTD/engine_interface_fdtd.h FDTD/engine_interface_fdtd.h \
Common/operator_base.h
QMAKE_CXXFLAGS_RELEASE = -O3 \ QMAKE_CXXFLAGS_RELEASE = -O3 \
-g \ -g \
-march=native -march=native