// =========================================================================== // // Filename: EMSchur3DBase.cpp // // Created: 09/20/2013 04:53:40 PM // Compiler: Tested with g++, icpc, and MSVC 2010 // // Author: Trevor Irons (ti) // // Organisation: University of Utah // // Email: Trevor.Irons@utah.edu // // =========================================================================== /** @file @author Trevor Irons @date 09/20/2013 **/ #include "EMSchur3DBase.h" typedef Eigen::Triplet Tc; typedef Eigen::Triplet Tr; // Moved to header //#define UPPER 0 // LOWER WAS 0 //#define LOWER 1 // 1=true, 0=false //#define FINITEVOLUME 1 #define FINITEDIFFERENCE 1 namespace Lemma { // ==================== FRIEND METHODS ===================== std::ostream &operator<<(std::ostream &stream, const EMSchur3DBase &ob) { stream << ob.Serialize() << "\n"; return stream; } // ==================== LIFECYCLE ======================= //-------------------------------------------------------------------------------------- // Class: EMSchur3DBase // Method: EMSchur3DBase // Description: constructor (protected) //-------------------------------------------------------------------------------------- // std::shared_ptr EMSchur3DBase::NewSP() { // return std::make_shared( ctor_key() ); // } //-------------------------------------------------------------------------------------- // Class: EMSchur3DBase // Method: EMSchur3DBase // Description: constructor (protected) //-------------------------------------------------------------------------------------- EMSchur3DBase::EMSchur3DBase ( const ctor_key& key ) : LemmaObject( key ), Grid(nullptr), //Survey(nullptr), LayModel(nullptr), Cvec(nullptr), ResFile("source"), sigma(nullptr), sigmap(nullptr) { } // ----- end of method EMSchur3DBase::EMSchur3DBase (constructor) ----- //-------------------------------------------------------------------------------------- // Class: EMSchur3DBase // Method: EMSchur3DBase // Description: constructor (protected) //-------------------------------------------------------------------------------------- EMSchur3DBase::EMSchur3DBase ( const YAML::Node& node, const ctor_key& key ) : LemmaObject( key ), Grid(nullptr), //Survey(nullptr), LayModel(nullptr), Cvec(nullptr), ResFile("source"), sigma(nullptr), sigmap(nullptr) { } // ----- end of method EMSchur3DBase::~EMSchur3DBase (destructor) ----- //-------------------------------------------------------------------------------------- // Class: EMSchur3DBase // Method: ~EMSchur3DBase // Description: destructor (protected) //-------------------------------------------------------------------------------------- EMSchur3DBase::~EMSchur3DBase ( ) { if (sigma) Delete3DScalar(sigma); if (sigmap) Delete3DScalar(sigmap); if (Cvec) delete [] Cvec; //if (CvecRe) delete [] CvecRe; } // ----- end of method EMSchur3DBase::~EMSchur3DBase (destructor) ----- //-------------------------------------------------------------------------------------- // Class: EMSchur3D // Method: Serialize //-------------------------------------------------------------------------------------- YAML::Node EMSchur3DBase::Serialize ( ) const { YAML::Node node = LemmaObject::Serialize(); node.SetTag( this->GetName() ); node["EMSchur3D_VERSION"] = EMSCHUR3D_VERSION; return node; } // ----- end of method EMSchur3D::Serialize ----- //-------------------------------------------------------------------------------------- // Class: EMSchur3DBase // Method: BuildC //-------------------------------------------------------------------------------------- void EMSchur3DBase::BuildC ( Real*** sigmax, Real*** sigmay, Real*** sigmaz, const int& iw) { Cvec[iw].resize( unx+uny+unz , unx+uny+unz ); #if LOWER && UPPER Cvec[iw].reserve(Eigen::VectorXi::Constant(unx+uny+unz, 7)); // Whole #else Cvec[iw].reserve(Eigen::VectorXi::Constant(unx+uny+unz, 4)); // Upper/Lower #endif //Cvec_s.resize( idx. ) //CMMvec[iw].resize( unx+uny+unz , unx+uny+unz ); //CMMvec[iw].reserve(Eigen::VectorXi::Constant(unx+uny+unz, 1)); Real omega = Omegas[iw]; std::cout << "Building C_" << iw << std::endl; //Complex hsig(0); Real hsig(0); Real EPS(1e-24); Real EPS2(1e-18); // book keeping int ir = 0; int ic = 0; // LAPL{Ax} + i omega mu sigmax for (int iz=0; iz(); return ; } // ----- end of method EMSchur3DBase::BuildC ----- //-------------------------------------------------------------------------------------- // Class: EMSchur3DBase // Method: BuildCReal //-------------------------------------------------------------------------------------- /* void EMSchur3DBase::BuildCReal ( Real*** sigmax, Real*** sigmay, Real*** sigmaz, const int& iw) { int CI = unx+uny+unz; CvecRe[iw].resize( 2*CI, 2*CI ); // twice the size, but Real std::vector triplets; triplets.reserve( 9*CI ); Real omega = Omegas[iw]; std::cout << "Building real C_" << iw << std::endl; // LAPL{Ax} + i omega mu sigmax int ir = 0; int ic = 0; Real hsig(0); Real EPS(1e-24); Real EPS2(1e-18); for (int iz=0; iz Csym; // Csym = Cvec[iw].selfadjointView(); // CMvec[iw].compute( Csym ); // return ; // } // ----- end of method EMSchur3DBase::BuildCPreconditioner ----- //-------------------------------------------------------------------------------------- // Class: EMSchur3DBase // Method: BuildD //-------------------------------------------------------------------------------------- void EMSchur3DBase::BuildD ( ) { D.resize(uns, unx+uny+unz ); //D.reserve(Eigen::VectorXi::Constant(unx+uny+unz, 6)); std::vector triplets; triplets.reserve( 2*unx + 2*uny + 2*unz ); std::cout << "Building D..."; int ic = 0; int ir = 0; //////////////////////////////// // Ax dx for (int iz=0; iz GridPtr ) { Grid = GridPtr; // Do some convienience stuff, we call these so often it's nice to not have to use // the accessors every time. This is the only place these are set. nx = Grid->GetNx(); ny = Grid->GetNy(); nz = Grid->GetNz(); hx = Grid->GetDx(); hy = Grid->GetDy(); hz = Grid->GetDz(); unx = (nx+1)*ny*nz; // Number of Vectors x component uny = nx*(ny+1)*nz; // Number of Vectors y component unz = nx*ny*(nz+1); // Number of Vectors z component uns = nx*ny*nz; // On dual grid, number of scalars ihx = 1. / hx.array(); ihy = 1. / hy.array(); ihz = 1. / hz.array(); ihx2 = 1. / (hx.array() * hx.array()); ihy2 = 1. / (hy.array() * hy.array()); ihz2 = 1. / (hz.array() * hz.array()); return ; } // ----- end of method EMSchur3DBase::SetRectilinearGrid ----- //-------------------------------------------------------------------------------------- // Class: EMSchur3DBase // Method: SetRectilinearGrid //-------------------------------------------------------------------------------------- void EMSchur3DBase::SetRectilinearGrid ( vtkRectilinearGrid* rGridPtr ) { // Convert to Lemma here } // ----- end of method EMSchur3DBase::SetRectilinearGrid ----- //-------------------------------------------------------------------------------------- // Class: EMSchur3DBase // Method: Setup //-------------------------------------------------------------------------------------- void EMSchur3DBase::Setup ( ) { //////////////////////////////////// // First set up grid stuff if (Cvec) delete [] Cvec; //if (CSolver) delete [] CSolver; Cvec = new Eigen::SparseMatrix [Omegas.size()]; //#ifdef LEMMAUSEOMP //#pragma omp parallel for schedule(static, 1) //#endif for (int iw=0; iw LayModelin ) { LayModel = LayModelin; return ; } // ----- end of method EMSchur3DBase::SetLayeredEarthEM ----- //-------------------------------------------------------------------------------------- // Class: EMSchur3DBase // Method: PrimaryField //-------------------------------------------------------------------------------------- void EMSchur3DBase::PrimaryField ( std::shared_ptr source, std::shared_ptr dpoint ) { auto EmEarth = Lemma::EMEarth1D::NewSP(); EmEarth->AttachDipoleSource(source); EmEarth->AttachLayeredEarthEM(LayModel); EmEarth->AttachFieldPoints(dpoint); EmEarth->SetFieldsToCalculate(Lemma::E); EmEarth->SetHankelTransformMethod(ANDERSON801); std::cout << "Primary Field Calculation" << std::endl; EmEarth->MakeCalc3(); return ; } // ----- end of method EMSchur3DBase::PrimaryField ----- //-------------------------------------------------------------------------------------- // Class: EMSchur3DBase // Method: FillPoints //-------------------------------------------------------------------------------------- void EMSchur3DBase::FillPoints ( std::shared_ptr dpoint) { dpoint->SetNumberOfPoints(unx + uny + unz); int ip(0); Real tx, ty, tz; Real ox = Grid->GetOx(); Real oy = Grid->GetOy(); Real oz = Grid->GetOz(); tz = oz; for (int iz=0; izSetLocation(ip, tx, ty, tz); if (ix < nx) tx += hx(ix); ++ip; } if (iySetLocation(ip, tx, ty, tz); if (ixSetLocation(ip, tx, ty, tz); if (ix ms, Eigen::Ref Se, Eigen::Ref E0, std::shared_ptr dpoint, const Real& omega ) { //Complex hsig(0); //Complex hsigp(0); Real hsig(0); Real hsigp(0); Real EPS(0); //1e-24); Real EPS2(1e-18); int iv = 0; for (int iz=0; izGetEfield(0,iv)(0); ms(iv) = MU0*hsig; Se(iv) = MU0*hsigp* dpoint->GetEfield(0,iv)(0); E0(iv) = dpoint->GetEfield(0,iv)(0); ++iv; } } } for (int iz=0; izGetEfield(0,iv)(1); ms(iv) = MU0*hsig; Se(iv) = MU0*hsigp* // TODO was hsigp !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! dpoint->GetEfield(0,iv)(1); E0(iv) = dpoint->GetEfield(0,iv)(1); ++iv; } } } for (int iz=0; izGetEfield(0, iv)(2); ms(iv) = MU0*hsig; Se(iv) = MU0*hsig *dpoint->GetEfield(0, iv)(2); E0(iv) = dpoint->GetEfield(0, iv)(2); ++iv; } } } return ; } // ----- end of method EMSchur3DBase::FillSourceTerms ----- VectorXcr EMSchur3DBase::StaggeredGridCurl( Eigen::Ref A ) { VectorXcr B = VectorXcr::Zero(3*nx*ny*nz); VectorXcr dzdy = VectorXcr::Zero( nx*ny*nz); VectorXcr dydz = VectorXcr::Zero( nx*ny*nz); VectorXcr dxdz = VectorXcr::Zero( nx*ny*nz); VectorXcr dzdx = VectorXcr::Zero( nx*ny*nz); VectorXcr dydx = VectorXcr::Zero( nx*ny*nz); VectorXcr dxdy = VectorXcr::Zero( nx*ny*nz); /* Curl_x = dzdy - dydz Curl_y = dxdz - dzdx Curl_z = dydx - dxdy */ //////////////////////////////// // X component int ii = 0; int iix = 0; for (int iz=0; iz A, Eigen::Ref Se, Eigen::Ref E0, Eigen::Ref E, Eigen::Ref Phi, Eigen::Ref ADiv, Eigen::Ref ADiv2, Eigen::Ref B ) { auto VTKGridExporter = RectilinearGridVTKExporter::NewSP(); VTKGridExporter->SetGrid(Grid); // VTK arrays to fill // scalars vtkDoubleArray *sigmaArray = vtkDoubleArray::New(); vtkDoubleArray *sigmapArray = vtkDoubleArray::New(); vtkDoubleArray *phiRealArray = vtkDoubleArray::New(); vtkDoubleArray *phiImagArray = vtkDoubleArray::New(); vtkDoubleArray *ADivRealArray = vtkDoubleArray::New(); vtkDoubleArray *ADivImagArray = vtkDoubleArray::New(); vtkDoubleArray *ADiv2RealArray = vtkDoubleArray::New(); vtkDoubleArray *ADiv2ImagArray = vtkDoubleArray::New(); // vectors vtkDoubleArray *AReal = vtkDoubleArray::New(); vtkDoubleArray *AImag = vtkDoubleArray::New(); vtkDoubleArray *BReal = vtkDoubleArray::New(); vtkDoubleArray *BImag = vtkDoubleArray::New(); vtkDoubleArray *SeReal = vtkDoubleArray::New(); vtkDoubleArray *SeImag = vtkDoubleArray::New(); vtkDoubleArray *E0Real = vtkDoubleArray::New(); vtkDoubleArray *E0Imag = vtkDoubleArray::New(); vtkDoubleArray *EReal = vtkDoubleArray::New(); vtkDoubleArray *EImag = vtkDoubleArray::New(); AReal->SetNumberOfComponents(3); AImag->SetNumberOfComponents(3); BReal->SetNumberOfComponents(3); BImag->SetNumberOfComponents(3); SeReal->SetNumberOfComponents(3); SeImag->SetNumberOfComponents(3); E0Real->SetNumberOfComponents(3); E0Imag->SetNumberOfComponents(3); EReal->SetNumberOfComponents(3); EImag->SetNumberOfComponents(3); // Interpolate Eigen::VectorXcd Ax(nx*ny*nz); // A Eigen::VectorXcd Ay(nx*ny*nz); Eigen::VectorXcd Az(nx*ny*nz); Eigen::VectorXcd Bx(nx*ny*nz); // B Eigen::VectorXcd By(nx*ny*nz); Eigen::VectorXcd Bz(nx*ny*nz); Eigen::VectorXcd Sex(nx*ny*nz); // Se Eigen::VectorXcd Sey(nx*ny*nz); Eigen::VectorXcd Sez(nx*ny*nz); Eigen::VectorXcd E0x(nx*ny*nz); // E0 Eigen::VectorXcd E0y(nx*ny*nz); Eigen::VectorXcd E0z(nx*ny*nz); Eigen::VectorXcd Ex(nx*ny*nz); // E Eigen::VectorXcd Ey(nx*ny*nz); Eigen::VectorXcd Ez(nx*ny*nz); //////////////////////////////// // X component int ii = 0; int iix = 0; int ic = 0; for (int iz=0; izGetVTKGrid(); int i = 0; for (int iz=0; izInsertTuple1(i, std::real(sigma[ix][iy][iz]) ); //sigmapArray->InsertTuple1(i, std::real(sigmap[ix][iy][iz]) ); sigmaArray->InsertTuple1(i, sigma[ix][iy][iz] ); sigmapArray->InsertTuple1(i, sigmap[ix][iy][iz] ); phiRealArray->InsertTuple1(i, std::real(Phi(i))); phiImagArray->InsertTuple1(i, std::imag(Phi(i))); ADivRealArray->InsertTuple1(i, std::real(ADiv(i))); ADivImagArray->InsertTuple1(i, std::imag(ADiv(i))); ADiv2RealArray->InsertTuple1(i, std::real(ADiv2(i))); ADiv2ImagArray->InsertTuple1(i, std::imag(ADiv2(i))); // vectors AReal->InsertTuple3(i, std::real(Ax(i)), std::real(Ay(i)), std::real(Az(i))); AImag->InsertTuple3(i, std::imag(Ax(i)), std::imag(Ay(i)), std::imag(Az(i))); BReal->InsertTuple3(i, std::real(Bx(i)), std::real(By(i)), std::real(Bz(i))); BImag->InsertTuple3(i, std::imag(Bx(i)), std::imag(By(i)), std::imag(Bz(i))); SeReal->InsertTuple3(i, std::real(Sex(i)), std::real(Sey(i)), std::real(Sez(i))); SeImag->InsertTuple3(i, std::imag(Sex(i)), std::imag(Sey(i)), std::imag(Sez(i))); E0Real->InsertTuple3(i, std::real(E0x(i)), std::real(E0y(i)), std::real(E0z(i))); E0Imag->InsertTuple3(i, std::imag(E0x(i)), std::imag(E0y(i)), std::imag(E0z(i))); EReal-> InsertTuple3(i, std::real(Ex(i)), std::real(Ey(i)), std::real(Ez(i))); EImag-> InsertTuple3(i, std::imag(Ex(i)), std::imag(Ey(i)), std::imag(Ez(i))); ++i; } } } AReal->SetName("A_real"); AImag->SetName("A_imag"); BReal->SetName("B_real"); BImag->SetName("B_imag"); SeReal->SetName("Se_real"); SeImag->SetName("Se_imag"); E0Real->SetName("E0_real"); E0Imag->SetName("E0_imag"); EReal->SetName("E_real"); EImag->SetName("E_imag"); phiRealArray->SetName("phi Real"); phiImagArray->SetName("phi imag"); ADivRealArray->SetName("ini div A real"); ADivImagArray->SetName("ini div A imag"); ADiv2RealArray->SetName("div A real"); ADiv2ImagArray->SetName("div A imag"); // Add scalar fields sigmaArray->SetName("sigma"); VTKGridExporter->GetVTKGrid()->GetCellData()->AddArray(sigmaArray); sigmapArray->SetName("sigma prime"); VTKGridExporter->GetVTKGrid()->GetCellData()->AddArray(sigmapArray); VTKGridExporter->GetVTKGrid()->GetCellData()->AddArray(phiRealArray); VTKGridExporter->GetVTKGrid()->GetCellData()->AddArray(phiImagArray); VTKGridExporter->GetVTKGrid()->GetCellData()->AddArray(ADivRealArray); VTKGridExporter->GetVTKGrid()->GetCellData()->AddArray(ADivImagArray); VTKGridExporter->GetVTKGrid()->GetCellData()->AddArray(ADiv2RealArray); VTKGridExporter->GetVTKGrid()->GetCellData()->AddArray(ADiv2ImagArray); // Add Vector Arrays VTKGridExporter->GetVTKGrid()->GetCellData()->AddArray(AReal); VTKGridExporter->GetVTKGrid()->GetCellData()->AddArray(AImag); VTKGridExporter->GetVTKGrid()->GetCellData()->AddArray(SeReal); VTKGridExporter->GetVTKGrid()->GetCellData()->AddArray(SeImag); VTKGridExporter->GetVTKGrid()->GetCellData()->AddArray(E0Real); VTKGridExporter->GetVTKGrid()->GetCellData()->AddArray(E0Imag); VTKGridExporter->GetVTKGrid()->GetCellData()->AddArray(EReal); VTKGridExporter->GetVTKGrid()->GetCellData()->AddArray(EImag); VTKGridExporter->GetVTKGrid()->GetCellData()->AddArray(BReal); VTKGridExporter->GetVTKGrid()->GetCellData()->AddArray(BImag); // Write vtkXMLRectilinearGridWriter *gridWrite = vtkXMLRectilinearGridWriter::New(); gridWrite->SetInputData( VTKGridExporter->GetVTKGrid() ); gridWrite->SetFileName( (fname + std::string(".vtr")).c_str()); gridWrite->Update(); gridWrite->Write(); sigmaArray->Delete(); gridWrite->Delete(); phiRealArray->Delete(); phiImagArray->Delete(); ADivRealArray->Delete(); ADivImagArray->Delete(); ADiv2RealArray->Delete(); ADiv2ImagArray->Delete(); // TODO delete vectors too! AReal->Delete(); AImag->Delete(); BReal->Delete(); BImag->Delete(); SeReal->Delete(); SeImag->Delete(); E0Real->Delete(); E0Imag->Delete(); EReal->Delete(); EImag->Delete(); return ; } // ----- end of method EMSchur3DBase::WriteVTKResults ----- //-------------------------------------------------------------------------------------- // Class: EMSchur3DBase // Method: LoadMeshToolsConductivityModel //-------------------------------------------------------------------------------------- void EMSchur3DBase::LoadMeshToolsConductivityModel ( const std::string& fname ) { if (sigma) Delete3DScalar(sigma); //Allocate3DScalar(sigma, Complex(0)); Allocate3DScalar(sigma, 0.); // TODO, there are smarter ways to do this, since the bacground is 1D. But for now, we just have // them the same. Eases logic in harmonic averaging. And it's just in one thread, so not so // hateful if (!LayModel) { std::cerr << "In EMSchur3DBase::LoadMeshToolsConductivityModel, you need to set your bacground 1D model\n"; exit(EXIT_FAILURE); } if (sigmap) Delete3DScalar(sigmap); //Allocate3DScalar(sigmap, Complex(0)); Allocate3DScalar(sigmap, 0.); auto Parser = ASCIIParser::NewSP(); Parser->Open(fname); std::vector sigmod = Parser->ReadReals( -1 ); if ( static_cast(sigmod.size()) != nx*ny*nz) { std::cerr << "In EMSchur3DBase::LoadMeshToolsConductivityModel model sizes are not in agreement\n"; exit(EXIT_FAILURE); } Parser->Close(); int ic(0); for (int ix=0; ixGetOz(); for (int iz=0; izGetLayerConductivity(LayModel->GetLayerAtThisDepth(pz)); sigmap[ix][iy][iz] = sigmod[ic] - LayModel->GetLayerConductivity(LayModel->GetLayerAtThisDepth(pz)).real() ; ++ic; pz += hz[iz]; } } } // Marker and cell MAC = VectorXi::Zero(nx*ny*nz); idx.clear(); ic = 0; for (int iz=0; iz 0.) { MAC(ic) = 1; idx.push_back(ic); } ++ic; } } } return ; } //-------------------------------------------------------------------------------------- // Class: EMSchur3DBase // Method: SetAEMSurvey //-------------------------------------------------------------------------------------- void EMSchur3DBase::SetAEMSurvey ( std::shared_ptr SurveyIn ) { Survey = SurveyIn; // determine how many frequencies we are dealing with Omegas = 2.*PI*Survey->GetFrequencies(); return ; } // ----- end of method EMSchur3DBase::SetAEMSurvey -----// ----- end of method EMSchur3DBase::LoadMeshToolsConductivityModel ----- //-------------------------------------------------------------------------------------- // Class: EMSchur3DBase // Method: Solve //-------------------------------------------------------------------------------------- void EMSchur3DBase::Solve ( ) { // TODO, these should throw exceptions for a GUI to catch if (!LayModel or !Survey or !Grid or !sigma) { std::cerr << "You need to set something. EMSChur3D::Solve()"; exit(EXIT_FAILURE); } //BuildD(); // strangely necessary, bug, track down. Setup(); std::cout << "Entering parallel solve" << std::endl; //#ifdef LEMMAUSEOMP //#pragma omp parallel for schedule(static,1) //#endif for (int isource=0; isourceGetNumberOfSources(); ++isource) { SolveSource(Survey->GetSource(isource), isource); } return ; } // ----- end of method EMSchur3DBase::Solve ----- } // ----- end of Lemma name -----