int bsp_om_save_file(char *filename, void * address, u32 length, u32 mode) { int ret = BSP_OK; int fd; int bytes; mm_segment_t old_fs; umode_t flag; old_fs = get_fs(); set_fs(KERNEL_DS); if(DUMP_SAVE_FILE_MODE_CREATE == mode) { flag = O_CREAT|O_WRONLY|O_TRUNC; } else { flag = O_CREAT|O_RDWR|O_APPEND; } fd = sys_open(filename, flag, 0755); if(fd < 0) { om_error("<bsp_om_save_file>, open failed! ret = %d\n", ret); ret = BSP_ERROR; goto out; } bytes = sys_write(fd, address, length); if(bytes != length) { om_error("<bsp_om_save_file>, write data failed! ret = %d\n", bytes); ret = BSP_ERROR; (void)sys_close(fd); goto out; } ret = sys_close(fd); if(0 != ret) { om_error("<bsp_om_save_file>, close file failed! ret = %d\n", ret); ret = BSP_ERROR; goto out; } ret = BSP_OK; out: set_fs(old_fs); return ret; }
void Geometry::generate_indices(const bool OLD_ORDERING) { // Either unknowns (potentials and currents) are ordered by mesh (i.e. V_1, p_1, V_2, p_2,...) (this is the OLD_ORDERING) // or by type (V_1,V_2,V_3 .. p_1, p_2...) (by DEFAULT) // or by the user himself encoded into the vtp file. // if you use OLD_ORDERING make sure to iterate only once on each vertex: not to overwrite index (meshes have shared vertices). if (begin()->begin()->index()==unsigned(-1)) { unsigned index = 0; if (!OLD_ORDERING) for (Vertices::iterator pit=vertex_begin();pit != vertex_end();++pit) (invalid_vertices_.empty()||invalid_vertices_.count(*pit)==0) ? pit->index()=index++ : unsigned(-1); for(iterator mit=begin();mit!=end();++mit){ if(OLD_ORDERING){ om_error(is_nested_); // OR non nested but without shared vertices for (Mesh::const_vertex_iterator vit=mit->vertex_begin();vit!=mit->vertex_end();++vit,++index) (*vit)->index() = index; } if(!mit->isolated()&&!mit->current_barrier()) for ( Mesh::iterator tit = mit->begin(); tit != mit->end(); ++tit) tit->index() = index++; } // even the last surface triangles (yes for EIT... ) nb_current_barrier_triangles()=0; for (iterator mit=begin(); mit!=end();++mit) if(mit->current_barrier()) if(!mit->isolated()){ nb_current_barrier_triangles()+=mit->nb_triangles(); for (Mesh::iterator tit=mit->begin(); tit!=mit->end(); ++tit) tit->index() = index++; } else { for(Mesh::iterator tit=mit->begin();tit!=mit->end();++tit) tit->index()=unsigned(-1); } size_ = index; }else{ std::cout << "vertex_begin()->index() " << vertex_begin()->index() << std::endl; size_ = vertices_.size(); for (iterator mit=begin();mit!=end();++mit) size_ += mit->size(); } }
void assemble_cortical2(const Geometry& geo, Matrix& mat, const Head2EEGMat& M, const std::string& domain_name, const unsigned gauss_order, double gamma, const std::string &filename) { // Re-writting of the optimization problem in M. Clerc, J. Kybic "Cortical mapping by Laplace–Cauchy transmission using a boundary element method". // with a Lagrangian formulation as in see http://www.math.uh.edu/~rohop/fall_06/Chapter3.pdf eq3.3 // find argmin(norm(gradient(X)) under constraints: // H * X = 0 and M * X = m // let G be the gradient norm matrix, l1, l2 the lagrange parameters // // [ G H' M'] [ X ] [ 0 ] // | H 0 | | l1 | = | 0 | // [ M 0 ] [ l2 ] [ m ] // // {----,----} // K // we want a submat of the inverse of K (using blockwise inversion, (TODO maybe iterative solution better ?)). // Assumptions: // - domain_name: the domain containing the sources is an innermost domain (defined as the interior of only one interface (called Cortex) // - Cortex interface is composed of one mesh only (no shared vertices) const Domain& SourceDomain = geo.domain(domain_name); const Interface& Cortex = SourceDomain.begin()->interface(); const Mesh& cortex = Cortex.begin()->mesh(); om_error(SourceDomain.size()==1); om_error(Cortex.size()==1); // shape of the new matrix: unsigned Nl = geo.size()-geo.nb_current_barrier_triangles()-Cortex.nb_vertices()-Cortex.nb_triangles(); unsigned Nc = geo.size()-geo.nb_current_barrier_triangles(); std::fstream f(filename.c_str()); Matrix H; if ( !f ) { // build the HeadMat: // The following is the same as assemble_HM except N_11, D_11 and S_11 are not computed. SymMatrix mat_temp(Nc); mat_temp.set(0.0); double K = 1.0 / (4.0 * M_PI); // We iterate over the meshes (or pair of domains) to fill the lower half of the HeadMat (since its symmetry) for ( Geometry::const_iterator mit1 = geo.begin(); mit1 != geo.end(); ++mit1) { for ( Geometry::const_iterator mit2 = geo.begin(); (mit2 != (mit1+1)); ++mit2) { // if mit1 and mit2 communicate, i.e they are used for the definition of a common domain const int orientation = geo.oriented(*mit1, *mit2); // equals 0, if they don't have any domains in common // equals 1, if they are both oriented toward the same domain // equals -1, if they are not if ( orientation != 0) { double Scoeff = orientation * geo.sigma_inv(*mit1, *mit2) * K; double Dcoeff = - orientation * geo.indicator(*mit1, *mit2) * K; double Ncoeff; if ( !(mit1->current_barrier() || mit2->current_barrier()) && ( (*mit1 != *mit2)||( *mit1 != cortex) ) ) { // Computing S block first because it's needed for the corresponding N block operatorS(*mit1, *mit2, mat_temp, Scoeff, gauss_order); Ncoeff = geo.sigma(*mit1, *mit2)/geo.sigma_inv(*mit1, *mit2); } else { Ncoeff = orientation * geo.sigma(*mit1, *mit2) * K; } if ( !mit1->current_barrier() && (( (*mit1 != *mit2)||( *mit1 != cortex) )) ) { // Computing D block operatorD(*mit1, *mit2, mat_temp, Dcoeff, gauss_order); } if ( ( *mit1 != *mit2 ) && ( !mit2->current_barrier() ) ) { // Computing D* block operatorD(*mit1, *mit2, mat_temp, Dcoeff, gauss_order, true); } // Computing N block if ( (*mit1 != *mit2)||( *mit1 != cortex) ) { operatorN(*mit1, *mit2, mat_temp, Ncoeff, gauss_order); } } } } // Deflate all current barriers as one deflat(mat_temp,geo); H = Matrix(Nl + M.nlin(), Nc); H.set(0.0); // copy mat_temp into H except the lines for cortex vertices [i_vb_c, i_ve_c] and cortex triangles [i_tb_c, i_te_c]. unsigned iNl = 0; for ( Geometry::const_iterator mit = geo.begin(); mit != geo.end(); ++mit) { if ( *mit != cortex ) { for ( Mesh::const_vertex_iterator vit = mit->vertex_begin(); vit != mit->vertex_end(); ++vit) { H.setlin(iNl, mat_temp.getlin((*vit)->index())); ++iNl; } if ( !mit->current_barrier() ) { for ( Mesh::const_iterator tit = mit->begin(); tit != mit->end(); ++tit) { H.setlin(iNl, mat_temp.getlin(tit->index())); ++iNl; } } } } if ( filename.length() != 0 ) { std::cout << "Saving matrix H (" << filename << ")." << std::endl; H.save(filename); } } else { std::cout << "Loading matrix H (" << filename << ")." << std::endl; H.load(filename); } // concat M to H for ( unsigned i = Nl; i < Nl + M.nlin(); ++i) { for ( unsigned j = 0; j < Nc; ++j) { H(i, j) = M(i-Nl, j); } } // ** Get the gradient of P1&P0 elements on the meshes ** SymMatrix G(Nc); G.set(0.); for ( Geometry::const_iterator mit = geo.begin(); mit != geo.end(); ++mit) { mit->gradient_norm2(G); } // multiply by gamma the submat of current gradient norm2 for ( Meshes::const_iterator mit = geo.begin(); mit != geo.end(); ++mit) { if ( !mit->current_barrier() ) { for ( Mesh::const_iterator tit1 = mit->begin(); tit1 != mit->end(); ++tit1) { for ( Mesh::const_iterator tit2 = mit->begin(); tit2 != mit->end(); ++tit2) { G(tit1->index(), tit2->index()) *= gamma; } } } } std::cout << "gamma = " << gamma << std::endl; G.invert(); mat = (G * H.transpose() * (H * G * H.transpose()).inverse()).submat(0, Nc, Nl, M.nlin()); }
void assemble_cortical(const Geometry& geo, Matrix& mat, const Head2EEGMat& M, const std::string& domain_name, const unsigned gauss_order, double alpha, double beta, const std::string &filename) { // Following the article: M. Clerc, J. Kybic "Cortical mapping by Laplace–Cauchy transmission using a boundary element method". // Assumptions: // - domain_name: the domain containing the sources is an innermost domain (defined as the interior of only one interface (called Cortex)) // - Cortex interface is composed of one mesh only (no shared vertices) const Domain& SourceDomain = geo.domain(domain_name); const Interface& Cortex = SourceDomain.begin()->interface(); const Mesh& cortex = Cortex.begin()->mesh(); om_error(SourceDomain.size()==1); om_error(Cortex.size()==1); // shape of the new matrix: unsigned Nl = geo.size()-geo.nb_current_barrier_triangles()-Cortex.nb_vertices()-Cortex.nb_triangles(); unsigned Nc = geo.size()-geo.nb_current_barrier_triangles(); std::fstream f(filename.c_str()); Matrix P; if ( !f ) { // build the HeadMat: // The following is the same as assemble_HM except N_11, D_11 and S_11 are not computed. SymMatrix mat_temp(Nc); mat_temp.set(0.0); double K = 1.0 / (4.0 * M_PI); // We iterate over the meshes (or pair of domains) to fill the lower half of the HeadMat (since its symmetry) for ( Geometry::const_iterator mit1 = geo.begin(); mit1 != geo.end(); ++mit1) { for ( Geometry::const_iterator mit2 = geo.begin(); (mit2 != (mit1+1)); ++mit2) { // if mit1 and mit2 communicate, i.e they are used for the definition of a common domain const int orientation = geo.oriented(*mit1, *mit2); // equals 0, if they don't have any domains in common // equals 1, if they are both oriented toward the same domain // equals -1, if they are not if ( orientation != 0) { double Scoeff = orientation * geo.sigma_inv(*mit1, *mit2) * K; double Dcoeff = - orientation * geo.indicator(*mit1, *mit2) * K; double Ncoeff; if ( !(mit1->current_barrier() || mit2->current_barrier()) && ( (*mit1 != *mit2)||( *mit1 != cortex) ) ) { // Computing S block first because it's needed for the corresponding N block operatorS(*mit1, *mit2, mat_temp, Scoeff, gauss_order); Ncoeff = geo.sigma(*mit1, *mit2)/geo.sigma_inv(*mit1, *mit2); } else { Ncoeff = orientation * geo.sigma(*mit1, *mit2) * K; } if ( !mit1->current_barrier() && (( (*mit1 != *mit2)||( *mit1 != cortex) )) ) { // Computing D block operatorD(*mit1, *mit2, mat_temp, Dcoeff, gauss_order,false); } if ( ( *mit1 != *mit2 ) && ( !mit2->current_barrier() ) ) { // Computing D* block operatorD(*mit1, *mit2, mat_temp, Dcoeff, gauss_order, true); } // Computing N block if ( (*mit1 != *mit2)||( *mit1 != cortex) ) { operatorN(*mit1, *mit2, mat_temp, Ncoeff, gauss_order); } } } } // Deflate all current barriers as one deflat(mat_temp,geo); mat = Matrix(Nl, Nc); mat.set(0.0); // copy mat_temp into mat except the lines for cortex vertices [i_vb_c, i_ve_c] and cortex triangles [i_tb_c, i_te_c]. unsigned iNl = 0; for ( Geometry::const_iterator mit = geo.begin(); mit != geo.end(); ++mit) { if ( *mit != cortex ) { for ( Mesh::const_vertex_iterator vit = mit->vertex_begin(); vit != mit->vertex_end(); ++vit) { mat.setlin(iNl, mat_temp.getlin((*vit)->index())); ++iNl; } if ( !mit->current_barrier() ) { for ( Mesh::const_iterator tit = mit->begin(); tit != mit->end(); ++tit) { mat.setlin(iNl, mat_temp.getlin(tit->index())); ++iNl; } } } } // ** Construct P: the null-space projector ** Matrix W; { Matrix U, s; mat.svd(U, s, W); } SparseMatrix S(Nc,Nc); // we set S to 0 everywhere, except in the last part of the diag: for ( unsigned i = Nl; i < Nc; ++i) { S(i, i) = 1.0; } P = (W * S) * W.transpose(); // P is a projector: P^2 = P and mat*P*X = 0 if ( filename.length() != 0 ) { std::cout << "Saving projector P (" << filename << ")." << std::endl; P.save(filename); } } else { std::cout << "Loading projector P (" << filename << ")." << std::endl; P.load(filename); } // ** Get the gradient of P1&P0 elements on the meshes ** Matrix MM(M.transpose() * M); SymMatrix RR(Nc, Nc); RR.set(0.); for ( Geometry::const_iterator mit = geo.begin(); mit != geo.end(); ++mit) { mit->gradient_norm2(RR); } // ** Choose Regularization parameter ** SparseMatrix alphas(Nc,Nc); // diagonal matrix Matrix Z; if ( alpha < 0 ) { // try an automatic method... TODO find better estimation double nRR_v = RR.submat(0, geo.nb_vertices(), 0, geo.nb_vertices()).frobenius_norm(); alphas.set(0.); alpha = MM.frobenius_norm() / (1.e3*nRR_v); beta = alpha * 50000.; for ( Vertices::const_iterator vit = geo.vertex_begin(); vit != geo.vertex_end(); ++vit) { alphas(vit->index(), vit->index()) = alpha; } for ( Meshes::const_iterator mit = geo.begin(); mit != geo.end(); ++mit) { if ( !mit->current_barrier() ) { for ( Mesh::const_iterator tit = mit->begin(); tit != mit->end(); ++tit) { alphas(tit->index(), tit->index()) = beta; } } } std::cout << "AUTOMATIC alphas = " << alpha << "\tbeta = " << beta << std::endl; } else { for ( Vertices::const_iterator vit = geo.vertex_begin(); vit != geo.vertex_end(); ++vit) { alphas(vit->index(), vit->index()) = alpha; } for ( Meshes::const_iterator mit = geo.begin(); mit != geo.end(); ++mit) { if ( !mit->current_barrier() ) { for ( Mesh::const_iterator tit = mit->begin(); tit != mit->end(); ++tit) { alphas(tit->index(), tit->index()) = beta; } } } std::cout << "alphas = " << alpha << "\tbeta = " << beta << std::endl; } Z = P.transpose() * (MM + alphas*RR) * P; // ** PseudoInverse and return ** // X = P * { (M*P)' * (M*P) + (R*P)' * (R*P) }¡(-1) * (M*P)'m // X = P * { P'*M'*M*P + P'*R'*R*P }¡(-1) * P'*M'm // X = P * { P'*(MM + a*RR)*P }¡(-1) * P'*M'm // X = P * Z¡(-1) * P' * M'm Matrix rhs = P.transpose() * M.transpose(); mat = P * Z.pinverse() * rhs; }
int om_clear_old_file(int fd, char * header) { int ret = BSP_OK; int i; int index; int head_len; int read_bytes; char *buf = BSP_NULL; struct linux_dirent *dir; char filename[OM_DUMP_FILE_MAX_NUM][OM_DUMP_FILE_NAME_LENGTH] = {{0},{0}}; char temp[OM_DUMP_FILE_NAME_LENGTH]; buf = kmalloc(1024, GFP_KERNEL); if(BSP_NULL == buf) { bsp_trace(BSP_LOG_LEVEL_ERROR, BSP_MODU_OM, "om_clear_old_file: Alloc mem error!"); return BSP_ERROR; } read_bytes = sys_getdents(fd, (struct linux_dirent *)buf, 1024); if(-1 == read_bytes) { /* 读取文件夹错误 */ om_error("<om_clear_old_file>, dents error!\n"); ret = BSP_ERROR; goto out; } if(0 == read_bytes) { /* 文件夹是空的,直接返回OK */ ret = BSP_OK; goto out; } /*轮询文件夹*/ head_len = strlen(header); for(i=0; i<read_bytes; ) { dir = (struct linux_dirent *)(buf + i); i += (int)dir->d_reclen; /* 删除旧的和错误的文件 */ if(0 == strncmp ((char *)dir->d_name, header, head_len)) { strncpy(temp, OM_ROOT_PATH, OM_DUMP_FILE_NAME_LENGTH-1); strncat(temp, dir->d_name, OM_DUMP_FILE_NAME_LENGTH-strlen(OM_ROOT_PATH)-1); index = simple_strtol(dir->d_name + head_len, NULL, 0); // 如果索引号超过最大值,或者有重复,直接删除文件 if((index >= OM_DUMP_FILE_MAX_NUM - 1) || (0 != filename[index][0])) { sys_unlink(temp); } else { strncpy(filename[index], temp, OM_DUMP_FILE_NAME_LENGTH -1); } } } /* 文件重命名 */ for(i=OM_DUMP_FILE_MAX_NUM-2; i>=0; i--) { if(filename[i][0]) { snprintf(temp, sizeof(temp), "%s%s%02d.bin", OM_ROOT_PATH, OM_DUMP_HEAD, i+1); /* coverity[check_return] */ (void)sys_rename(filename[i], temp); } } out: if(buf) kfree(buf); return ret; }
int bsp_om_append_file(char *filename, void * address, u32 length, u32 max_size) { int ret = BSP_OK; int fd; int bytes; int len; mm_segment_t old_fs; old_fs = get_fs(); set_fs(KERNEL_DS); ret = om_create_dir(OM_ROOT_PATH); if(BSP_OK != ret) { om_error("<bsp_om_append_file>, create dir failed! ret = %d\n", ret); goto out; } /* open file */ ret = sys_access(filename, 0); if(BSP_OK != ret) { /*create file */ fd = sys_open(filename, O_CREAT|O_RDWR, 0755); if(fd < 0) { om_error("<bsp_om_append_file>, open failed while mode is create, ret = %d\n", fd); goto out; } } else { fd = sys_open(filename, O_APPEND|O_RDWR, 0755); if(fd < 0) { om_error("<bsp_om_append_file>, open failed while mode is append, ret = %d\n", fd); goto out; } } len = sys_lseek(fd, 0, SEEK_END); if(ERROR == len) { om_error("<bsp_om_append_file>, seek failed! ret = %d\n", len); (void)sys_close(fd); goto out; } if (len >= max_size) { sys_close(fd); ret = sys_unlink(filename); if (OK != ret) { om_error("<bsp_om_append_file>, remove failed! ret = %d\n", ret); goto out; } /*重新建立reset文件*/ fd = sys_open(filename, O_CREAT|O_RDWR, 0755); if(fd < 0) { om_error("<bsp_om_append_file>, create failed! ret = %d\n", fd); goto out; } } bytes = sys_write(fd, address, length); if(bytes != length) { om_error("<bsp_om_append_file>, write data failed! ret = %d\n", bytes); ret = BSP_ERROR; (void)sys_close(fd); goto out; } ret = sys_close(fd); if(0 != ret) { om_error("<bsp_om_append_file>, close failed! ret = %d\n", ret); ret = BSP_ERROR; goto out; } ret = BSP_OK; out: set_fs(old_fs); return ret; }
int bsp_om_save_loop_file(char * dirName, char *fileHeader, void * address, u32 length) { int ret = BSP_OK; int fd; int bytes; mm_segment_t old_fs; char newFileName[OM_DUMP_FILE_NAME_LENGTH] = {0}; /* 进入目录 */ if (NULL == dirName || NULL == fileHeader) { om_error("<bsp_om_save_loop_file>, file name NULL!\n"); return BSP_ERROR; } if ((strlen((const char*)dirName) + strlen((const char*)fileHeader)) >= OM_DUMP_FILE_NAME_LENGTH) { om_error("<bsp_om_save_loop_file>, file name too long!\n"); return BSP_ERROR; } old_fs = get_fs(); set_fs(KERNEL_DS); fd = om_open_dir(dirName); if(fd < 0) { om_error("<bsp_om_save_loop_file>, open om dir failed! ret = %d\n", ret); ret = BSP_ERROR; goto out; } ret = om_clear_old_file(fd, fileHeader); if(BSP_OK != ret) { om_error("<bsp_om_save_loop_file>, clear old file failed! ret = %d\n", ret); ret = BSP_ERROR; goto out; } om_close_dir(fd); //新文件名:0 memset(newFileName, 0, sizeof(newFileName)); snprintf(newFileName, sizeof(newFileName), "%s%s%02d.bin", dirName, fileHeader, 0); fd = sys_creat(newFileName, 0755); if(fd < 0) { om_error("<bsp_om_save_loop_file>, creat file failed! ret = %d\n", ret); ret = BSP_ERROR; goto out; } bytes = sys_write(fd, address, length); if(bytes != length) { om_error("<bsp_om_save_loop_file>, write data to file failed! ret = %d\n", bytes); ret = BSP_ERROR; (void)sys_close(fd); goto out; } ret = sys_close(fd); if(0 != ret) { om_error("<bsp_om_save_loop_file>, close file failed! ret = %d\n", ret); ret = BSP_ERROR; goto out; } ret = BSP_OK; out: set_fs(old_fs); return ret; }