void SPlaneSlicer::applySliceTranslation(vtkSmartPointer<vtkMatrix4x4> vtkMat) const { auto image = this->getInput< ::fwData::Image >(s_EXTENT_IN); ::fwData::Object::sptr index; switch (m_orientation) { case ::fwDataTools::helper::MedicalImageAdaptor::Orientation::X_AXIS: index = image->getField(::fwDataTools::fieldHelper::Image::m_sagittalSliceIndexId); break; case ::fwDataTools::helper::MedicalImageAdaptor::Orientation::Y_AXIS: index = image->getField(::fwDataTools::fieldHelper::Image::m_frontalSliceIndexId); break; case ::fwDataTools::helper::MedicalImageAdaptor::Orientation::Z_AXIS: index = image->getField(::fwDataTools::fieldHelper::Image::m_axialSliceIndexId); break; } const int idx = ::fwData::Integer::dynamicCast(index)->value(); const auto& spacing = image->getSpacing(); const auto& origin = image->getOrigin(); const std::uint8_t axis = static_cast<std::uint8_t>(m_orientation); const double trans = spacing[axis] * static_cast<double>(idx) + origin[axis]; vtkSmartPointer<vtkMatrix4x4> transMat = vtkSmartPointer<vtkMatrix4x4>::New(); transMat->Identity(); transMat->SetElement(axis, 3, trans); vtkMatrix4x4::Multiply4x4(vtkMat, transMat, vtkMat); }
void SPlaneSlicer::updating() { this->setReslicerExtent(); this->setReslicerAxes(); auto image = this->getInput< ::fwData::Image >(s_IMAGE_IN); vtkSmartPointer<vtkImageData> vtkimg = vtkSmartPointer<vtkImageData>::New(); ::fwVtkIO::toVTKImage(image, vtkimg.Get()); m_reslicer->SetInputData(vtkimg); m_reslicer->Update(); auto slice = this->getInOut< ::fwData::Image >(s_SLICE_OUT); ::fwVtkIO::fromVTKImage(m_reslicer->GetOutput(), slice); // HACK: Make output slice three-dimensional. // We need to do so in order to visualize it with ::visuVTKAdaptor::SImageSlice. // This is because the adaptor uses a vtkImageActor which doesn't handle 2d images. auto size = slice->getSize(); slice->setSize({{size[0], size[1], 1}}); auto spacing = slice->getSpacing(); slice->setSpacing({{spacing[0], spacing[1], 0 }}); auto origin = slice->getOrigin(); slice->setOrigin({{origin[0], origin[1], 0}}); auto sig = slice->signal< ::fwData::Image::ModifiedSignalType >(::fwData::Image::s_MODIFIED_SIG); sig->asyncEmit(); }
Module* PacketCountFilterCfg::getInstance() { if (!instance) instance = new SystematicSampler(SYSTEMATIC_SAMPLER_COUNT_BASED, getInterval(), getSpacing()); return (Module*)instance; }
void HorizontalListLayout::setBoxes(Layouter::LayoutedWidgets &widgets) { float x = 0; for(std::shared_ptr<PiH::Widget> &widget : widgets) { widget->setBoundingBox(x, getBoundingBox().y, widget->getBoundingBox().w, getBoundingBox().h); x += widget->getBoundingBox().w + getSpacing(); } }
void tmx::Tileset::tell() { std::cout << "Name: " << getName() << "\n" << "Source: " << getSource() << "\n" << "First gID: " << getFirstGid() << "\n" << "Tile Width: " << getTileWidth() << "\n" << "Tile Height: " << getTileHeight() << "\n" << "Spacing: " << getSpacing() << "\n" << "Margin: " << getMargin() << std::endl; }
void checkImages(cx::ImagePtr input, cx::ImagePtr expected) { { INFO(getDim(input) << " == " << getDim(expected)); CHECK(cx::similar(getDim(input), getDim(expected))); } { INFO(input->get_rMd() << "\n == \n" << expected->get_rMd()); CHECK(cx::similar(input->get_rMd(), expected->get_rMd())); } { INFO(getSpacing(input) << " == " << getSpacing(expected)); CHECK(cx::similar(getSpacing(input), getSpacing(expected))); } CHECK(input->getParentSpace() == expected->getParentSpace()); // removed: image is not necessarily black. The size is what matters. //CHECK(cxtest::Utilities::getFractionOfVoxelsAboveThreshold(input->getBaseVtkImageData(), 0) == Approx(0)); }
void VerticalListLayout::setBoxes(Layouter::LayoutedWidgets &widgets) { float x = getBoundingBox().x, y = getBoundingBox().y; for(std::shared_ptr<PiH::Widget> &widget : widgets) { if(m_centered) { x = getBoundingBox().x + getBoundingBox().w / 2 - widget->getBoundingBox().w / 2; } widget->setBoundingBox(x, y, widget->getBoundingBox().w, widget->getBoundingBox().h); y += widget->getBoundingBox().h + getSpacing(); } }
/** * Returns the dimensions of a particular character in the font. * @param c Font character. * @return Width and Height dimensions (X and Y are ignored). */ SDL_Rect Font::getCharSize(wchar_t c) { SDL_Rect size = { 0, 0, 0, 0 }; if (c != 1 && !isLinebreak(c) && !isSpace(c)) { FontImage *image = &_images[_chars[c].first]; size.w = _chars[c].second.w + image->spacing; size.h = _chars[c].second.h + image->spacing; } else { if (_monospace) size.w = getWidth() + getSpacing(); else if (isNonBreakableSpace(c)) size.w = getWidth() / 4; else size.w = getWidth() / 2; size.h = getHeight() + getSpacing(); } // In case anyone mixes them up size.x = size.w; size.y = size.h; return size; }
//======================================================================== // // NAME GFXFont::wrapStr // // DESCRIPTION // modifies *str so that it will word wrap within the // specified width. Carriage returns are removed // and replaced with spaces or spaces are removed and // replaced by carriage returns. // // ARGUMENTS // str - String to be modified // width - wrapping width in pixels // RETURNS // // NOTES // Tabs are not supported. // //======================================================================== void GFXFont::wrapStr(char *str, Int32 width) { Int32 spaceLen; // length of a space character Int32 lineLen; // length of current line Int32 wordLen; // length of current word char *lastSpace; spaceLen = getWidth(' ') + getSpacing(); lineLen = 0; lastSpace = NULL; while (*str) { // convert spaces if (isspace(*str)) { lineLen += spaceLen; *str = ' '; lastSpace = str; str++; } else { wordLen = getWordWidth((void *)str); if ((lineLen + wordLen) > width) { if (lastSpace) { *lastSpace = '\n'; lastSpace = NULL; lineLen = 0; } } lineLen += wordLen; while (*str && (! isspace(*str)) ) str++; } } }
RRect RLineCache::flush(class IRichCompositor* compositor) { RRect line_rect; // no element yet, need not flush! element_list_t* line = getCachedElements(); if ( line->size() == 0 ) return line_rect; // line mark std::vector<element_list_t::iterator> line_marks; std::vector<short> line_widths; RRect zone = compositor->getMetricsState()->zone; bool wrapline = m_rWrapLine; // line width auto growth if ( zone.size.w == 0 ) wrapline = false; RMetricsState* mstate = compositor->getMetricsState(); RPos pen; RRect temp_linerect; short base_line_pos_y = 0; element_list_t::iterator inner_start_it = line->begin(); line_marks.push_back(line->begin()); // push first line start for ( element_list_t::iterator it = line->begin(); it != line->end(); it++ ) { RMetrics* metrics = (*it)->getMetrics(); // prev composit event (*it)->onCachedCompositBegin(this, pen); // calculate baseline offset short baseline_correct = 0; if ( (*it)->needBaselineCorrect() ) { baseline_correct = m_rBaselinePos; } // first element if ( pen.x == 0 ) { pen.x -= metrics->rect.min_x(); } // set position (*it)->setLocalPositionX(pen.x); (*it)->setLocalPositionY(pen.y + baseline_correct); RRect rect = metrics->rect; rect.pos.x += pen.x; rect.pos.y += baseline_correct; temp_linerect.extend(rect); // process wrapline element_list_t::iterator next_it = it + 1; if ( next_it == line->end() || // last element (*next_it)->isNewlineBefore() || // line-break before next element (*it)->isNewlineFollow() || // line-break after this element ( wrapline && pen.x != 0 // wrap line && pen.x + metrics->advance.x + (*next_it)->getMetrics()->rect.pos.x + (*next_it)->getMetrics()->rect.size.w + getPadding()*2 > zone.size.w && (*next_it)->canLinewrap() ) ) { // correct out of bound correct short y2correct = -temp_linerect.max_y(); for ( element_list_t::iterator inner_it = inner_start_it; inner_it != next_it; inner_it++ ) { RPos pos = (*inner_it)->getLocalPosition(); (*inner_it)->setLocalPositionY(pos.y + y2correct); (*inner_it)->setLocalPositionX(pos.x /*+ x2correct*/); } temp_linerect.pos.y = pen.y; line_rect.extend(temp_linerect); pen.y -= (temp_linerect.size.h + getSpacing()); pen.x = 0; // push next line start line_marks.push_back(next_it); line_widths.push_back(temp_linerect.size.w); inner_start_it = next_it; temp_linerect = RRect(); } else { pen.x += metrics->advance.x; } // post composit event (*it)->onCachedCompositEnd(this, pen); } short align_correct_x = 0; size_t line_mark_idx = 0; if ( getHAlign() == e_align_left ) line_rect.size.w += getPadding() * 2; else line_rect.size.w = RMAX(zone.size.w, line_rect.size.w + getPadding() * 2); // auto rect for ( element_list_t::iterator it = line->begin(); it != line->end(); it++ ) { // prev composit event (*it)->onCachedCompositBegin(this, pen); if ( it == line_marks[line_mark_idx] ) { short lwidth = line_widths[line_mark_idx]; // x correct switch ( getHAlign() ) { case e_align_left: align_correct_x = getPadding(); break; case e_align_center: align_correct_x = ( line_rect.size.w - lwidth ) / 2; break; case e_align_right: align_correct_x = line_rect.size.w - lwidth - getPadding(); break; } line_mark_idx++; // until next line } RPos pos = (*it)->getLocalPosition(); (*it)->setLocalPositionX(mstate->pen_x + pos.x + align_correct_x); (*it)->setLocalPositionY(mstate->pen_y + pos.y); // post composit event (*it)->onCachedCompositEnd(this, pen); } line_rect.pos.y = mstate->pen_y; // advance pen position mstate->pen_y -= (line_rect.size.h + getSpacing()); mstate->pen_x = 0; clear(); return line_rect; }
RRect RHTMLTableCache::flush(class IRichCompositor* compositor) { RRect table_rect; if ( m_rCached.empty()) { return table_rect; } // table content size std::vector<short> row_heights; std::vector<short> col_widths; std::vector<bool> width_set; short max_row_width = 0; short max_row_height = 0; for ( element_list_t::iterator it = m_rCached.begin(); it != m_rCached.end(); it++ ) { REleHTMLRow* row = dynamic_cast<REleHTMLRow*>(*it); if ( !row ) { CCLog("[CCRich] Table cache can only accept 'REleHTMLRow' element!"); continue; } short current_row_height = 0; std::vector<class REleHTMLCell*>& cells = row->getCells(); for ( size_t i = 0; i < cells.size(); i++ ) { CCAssert(i <= col_widths.size(), ""); if ( i == col_widths.size() ) { col_widths.push_back(cells[i]->getMetrics()->rect.size.w + getPadding() * 2); width_set.push_back(cells[i]->isWidthSet()); } else { if (width_set[i]) { if (cells[i]->isWidthSet()) { col_widths[i] = RMAX(col_widths[i], cells[i]->getMetrics()->rect.size.w + getPadding() * 2); } else { // do nothing } } else { if (cells[i]->isWidthSet()) { col_widths[i] = cells[i]->getMetrics()->rect.size.w + getPadding() * 2; width_set[i] = true; } else { // do nothing use the first row default width //col_widths[i] = RMIN(col_widths[i], cells[i]->getMetrics()->rect.size.w + getPadding() * 2); } } } current_row_height = RMAX(current_row_height, cells[i]->getMetrics()->rect.size.h); } current_row_height += getPadding() * 2; row_heights.push_back(current_row_height); table_rect.size.h += current_row_height; } // max width for ( size_t i = 0; i < col_widths.size(); i++ ) { table_rect.size.w += col_widths[i]; } // set content metrics short spacing = getSpacing(); short pen_x = 0; short pen_y = -m_rTable->m_rBorder; size_t row_idx = 0; for ( element_list_t::iterator it = m_rCached.begin(); it != m_rCached.end(); it++ ) { REleHTMLRow* row = dynamic_cast<REleHTMLRow*>(*it); if ( !row ) { CCLog("[CCRich] Table cache can only accept 'REleHTMLRow' element!"); continue; } pen_x = m_rTable->m_rBorder; // set row metrics row->setLocalPositionX(pen_x); row->setLocalPositionY(pen_y); RMetrics* row_metrics = row->getMetrics(); row_metrics->rect.size.h = row_heights[row_idx]; row_metrics->rect.size.w = table_rect.size.w + spacing * (col_widths.size() - 1); // process cells in row short cell_pen_x = 0; std::vector<class REleHTMLCell*>& cells = row->getCells(); for ( size_t i = 0; i < cells.size(); i++ ) { cells[i]->setLocalPositionX(cell_pen_x); cells[i]->setLocalPositionY(0); RMetrics* cell_metrics = cells[i]->getMetrics(); cell_metrics->rect.size.w = col_widths[i]; cell_metrics->rect.size.h = row_heights[row_idx]; recompositCell(cells[i]); cell_pen_x += col_widths[i]; cell_pen_x += spacing; } pen_y -= row_heights[row_idx]; pen_y -= spacing; row_idx++; } table_rect.size.h += m_rTable->m_rBorder * 2 + spacing * (row_heights.size() - 1); table_rect.size.w += m_rTable->m_rBorder * 2 + spacing * (col_widths.size() - 1); m_rCached.clear(); return table_rect; }
bool FieldPlane::accumulate(FieldPlane fp) { return getCenter() == fp.getCenter() && getSpacing() == fp.getSpacing() ? accumulateSquare(fp.get()) : false; }
bool FieldPlane::sum(FieldPlane fp) { return getCenter() == fp.getCenter() && getSpacing() == fp.getSpacing() ? sum(fp.get()) : false; }
int main(int argc, char* argv[]) { /*! * \page Vector_5_md_vl_sym_crs Vector 5 molecular dynamic with symmetric Verlet list crossing scheme * * ## Simulation ## {#md_e5_sym_sim_crs} * * The simulation is equal to the simulation explained in the example molecular dynamic * * \see \ref md_e5_sym * * The difference is that we create a symmetric Verlet-list for crossing scheme instead of a normal one * \snippet Vector/5_molecular_dynamic_sym_crs/main.cpp sim verlet * * The rest of the code remain unchanged * * \snippet Vector/5_molecular_dynamic_sym_crs/main.cpp simulation * */ //! \cond [simulation] \endcond double dt = 0.00025; double sigma = 0.1; double r_cut = 3.0*sigma; double r_gskin = 1.3*r_cut; double sigma12 = pow(sigma,12); double sigma6 = pow(sigma,6); openfpm::vector<double> x; openfpm::vector<openfpm::vector<double>> y; openfpm_init(&argc,&argv); Vcluster & v_cl = create_vcluster(); // we will use it do place particles on a 10x10x10 Grid like size_t sz[3] = {10,10,10}; // domain Box<3,float> box({0.0,0.0,0.0},{1.0,1.0,1.0}); // Boundary conditions size_t bc[3]={PERIODIC,PERIODIC,PERIODIC}; // ghost, big enough to contain the interaction radius Ghost<3,float> ghost(r_gskin); ghost.setLow(0,0.0); ghost.setLow(1,0.0); ghost.setLow(2,0.0); vector_dist<3,double, aggregate<double[3],double[3]> > vd(0,box,bc,ghost,BIND_DEC_TO_GHOST); size_t k = 0; size_t start = vd.accum(); auto it = vd.getGridIterator(sz); while (it.isNext()) { vd.add(); auto key = it.get(); vd.getLastPos()[0] = key.get(0) * it.getSpacing(0); vd.getLastPos()[1] = key.get(1) * it.getSpacing(1); vd.getLastPos()[2] = key.get(2) * it.getSpacing(2); vd.template getLastProp<velocity>()[0] = 0.0; vd.template getLastProp<velocity>()[1] = 0.0; vd.template getLastProp<velocity>()[2] = 0.0; vd.template getLastProp<force>()[0] = 0.0; vd.template getLastProp<force>()[1] = 0.0; vd.template getLastProp<force>()[2] = 0.0; k++; ++it; } vd.map(); vd.ghost_get<>(); timer tsim; tsim.start(); //! \cond [sim verlet] \endcond // Get the Cell list structure auto NN = vd.getVerletCrs(r_gskin);; //! \cond [sim verlet] \endcond // calculate forces calc_forces(vd,NN,sigma12,sigma6,r_cut); unsigned long int f = 0; int cnt = 0; double max_disp = 0.0; // MD time stepping for (size_t i = 0; i < 10000 ; i++) { // Get the iterator auto it3 = vd.getDomainIterator(); double max_displ = 0.0; // integrate velicity and space based on the calculated forces (Step1) while (it3.isNext()) { auto p = it3.get(); // here we calculate v(tn + 0.5) vd.template getProp<velocity>(p)[0] += 0.5*dt*vd.template getProp<force>(p)[0]; vd.template getProp<velocity>(p)[1] += 0.5*dt*vd.template getProp<force>(p)[1]; vd.template getProp<velocity>(p)[2] += 0.5*dt*vd.template getProp<force>(p)[2]; Point<3,double> disp({vd.template getProp<velocity>(p)[0]*dt,vd.template getProp<velocity>(p)[1]*dt,vd.template getProp<velocity>(p)[2]*dt}); // here we calculate x(tn + 1) vd.getPos(p)[0] += disp.get(0); vd.getPos(p)[1] += disp.get(1); vd.getPos(p)[2] += disp.get(2); if (disp.norm() > max_displ) max_displ = disp.norm(); ++it3; } if (max_disp < max_displ) max_disp = max_displ; // Because we moved the particles in space we have to map them and re-sync the ghost if (cnt % 10 == 0) { vd.map(); vd.template ghost_get<>(); // Get the Cell list structure vd.updateVerlet(NN,r_gskin,VL_CRS_SYMMETRIC); } else { vd.template ghost_get<>(SKIP_LABELLING); } cnt++; // calculate forces or a(tn + 1) Step 2 calc_forces(vd,NN,sigma12,sigma6,r_cut); // Integrate the velocity Step 3 auto it4 = vd.getDomainIterator(); while (it4.isNext()) { auto p = it4.get(); // here we calculate v(tn + 1) vd.template getProp<velocity>(p)[0] += 0.5*dt*vd.template getProp<force>(p)[0]; vd.template getProp<velocity>(p)[1] += 0.5*dt*vd.template getProp<force>(p)[1]; vd.template getProp<velocity>(p)[2] += 0.5*dt*vd.template getProp<force>(p)[2]; ++it4; } // After every iteration collect some statistic about the confoguration if (i % 100 == 0) { // We write the particle position for visualization (Without ghost) vd.deleteGhost(); vd.write("particles_",f); // we resync the ghost vd.ghost_get<>(); // We calculate the energy double energy = calc_energy(vd,NN,sigma12,sigma6,r_cut); auto & vcl = create_vcluster(); vcl.sum(energy); vcl.max(max_disp); vcl.execute(); // we save the energy calculated at time step i c contain the time-step y contain the energy x.add(i); y.add({energy}); // We also print on terminal the value of the energy // only one processor (master) write on terminal if (vcl.getProcessUnitID() == 0) std::cout << "Energy: " << energy << " " << max_disp << " " << std::endl; max_disp = 0.0; f++; } } tsim.stop(); std::cout << "Time: " << tsim.getwct() << std::endl; //! \cond [simulation] \endcond // Google charts options, it store the options to draw the X Y graph GCoptions options; // Title of the graph options.title = std::string("Energy with time"); // Y axis name options.yAxis = std::string("Energy"); // X axis name options.xAxis = std::string("iteration"); // width of the line options.lineWidth = 1.0; // Object that draw the X Y graph GoogleChart cg; // Add the graph // The graph that it produce is in svg format that can be opened on browser cg.AddLinesGraph(x,y,options); // Write into html format cg.write("gc_plot2_out.html"); //! \cond [google chart] \endcond /*! * \page Vector_5_md_vl_sym_crs Vector 5 molecular dynamic with symmetric Verlet list crossing scheme * * ## Finalize ## {#finalize_v_e5_md_sym_crs} * * At the very end of the program we have always to de-initialize the library * * \snippet Vector/5_molecular_dynamic_sym_crs/main.cpp finalize * */ //! \cond [finalize] \endcond openfpm_finalize(); //! \cond [finalize] \endcond /*! * \page Vector_5_md_vl_sym_crs Vector 5 molecular dynamic with symmetric Verlet list crossing scheme * * ## Full code ## {#full_code_v_e5_md_sym_crs} * * \include Vector/5_molecular_dynamic_sym_crs/main.cpp * */ }
int main(int argc, char* argv[]) { /*! * * \page Vector_4_comp_reo Vector 4 computational reordering and cache friendliness * * ## Initialization ## * * The initialization is the same as the molecular dynamic example. The differences are in the * parameters. We will use a bigger system, with more particles. The delta time for integration * is chosen in order to keep the system stable. * * \see \ref e3_md_init * * \snippet Vector/4_reorder/main_comp_ord.cpp vect create * */ //! \cond [vect create] \endcond double dt = 0.0001; float r_cut = 0.03; double sigma = r_cut/3.0; double sigma12 = pow(sigma,12); double sigma6 = pow(sigma,6); openfpm::vector<double> x; openfpm::vector<openfpm::vector<double>> y; openfpm_init(&argc,&argv); Vcluster & v_cl = create_vcluster(); // we will use it do place particles on a 40x40x40 Grid like size_t sz[3] = {40,40,40}; // domain Box<3,float> box({0.0,0.0,0.0}, {1.0,1.0,1.0}); // Boundary conditions size_t bc[3]= {PERIODIC,PERIODIC,PERIODIC}; // ghost, big enough to contain the interaction radius Ghost<3,float> ghost(r_cut); vector_dist<3,double, aggregate<double[3],double[3]> > vd(0,box,bc,ghost); //! \cond [vect create] \endcond /*! * \page Vector_4_comp_reo Vector 4 computational reordering and cache friendliness * * ## Particles on a grid like position ## * * Here we place the particles on a grid like manner * * \see \ref e3_md_gl * * \snippet Vector/4_reorder/main_comp_ord.cpp vect grid * */ //! \cond [vect grid] \endcond auto it = vd.getGridIterator(sz); while (it.isNext()) { vd.add(); auto key = it.get(); vd.getLastPos()[0] = key.get(0) * it.getSpacing(0); vd.getLastPos()[1] = key.get(1) * it.getSpacing(1); vd.getLastPos()[2] = key.get(2) * it.getSpacing(2); vd.template getLastProp<velocity>()[0] = 0.0; vd.template getLastProp<velocity>()[1] = 0.0; vd.template getLastProp<velocity>()[2] = 0.0; vd.template getLastProp<force>()[0] = 0.0; vd.template getLastProp<force>()[1] = 0.0; vd.template getLastProp<force>()[2] = 0.0; ++it; } //! \cond [vect grid] \endcond /*! * * \page Vector_4_comp_reo Vector 4 computational reordering and cache friendliness * * ## Molecular dynamic steps ## * * Here we do 30000 MD steps using verlet integrator the cycle is the same as the * molecular dynamic example. with the following changes. * * ### Cell lists ### * * Instead of getting the normal cell list we get an hilbert curve cell-list. Such cell list has a * function called **getIterator** used inside the function **calc_forces** and **calc_energy** * that iterate across all the particles but in a smart-way. In practice * given an r-cut a cell-list is constructed with the provided spacing. Suppose to have a cell-list * \f$ m \times n \f$, an hilbert curve \f$ 2^k \times 2^k \f$ is contructed with \f$ k = ceil(log_2(max(m,n))) \f$. * Cell-lists are explored according to this Hilbert curve, If a cell does not exist is simply skipped. * * * \verbatim +------+------+------+------+ Example of Hilbert curve running on a 3 x 3 Cell | | | | | An hilbert curve of k = ceil(log_2(3)) = 4 | X+---->X | X +---> X | | ^ | + | ^ | + | ***|******|******|****---|--+ ******* * + | v | + * v | * * * 7 | 8+---->9 * X | * * = Domain * ^ | | * + | * * *--|-----------------*---|--+ ******* * + | | * v | * 4<----+5 | 6<---+ X | * | ^ | + * | *---------|-------|--*------+ * | + | v * | * 1+---->2 | 3+---> X | * | | * | **********************------+ this mean that we will iterate the following cells 1,2,5,4,7,8,9,6,3 Suppose now that the particles are ordered like described Particles id Cell 0 1 1 7 2 8 3 1 4 9 5 9 6 6 7 7 8 3 9 2 10 4 11 3 The iterator of the cell-list will explore the particles in the following way Cell 1 2 5 4 7 8 9 6 3 | | | | | | | | | | 0,3,9,,10,1,7,2,4,5,6,8 * \endverbatim * * We cannot explain here what is a cache, but in practice is a fast memory in the CPU able * to store chunks of memory. The cache in general is much smaller than RAM, but the big advantage * is its speed. Retrieve data from the cache is much faster than RAM. Unfortunately the factors * that determine what is on cache and what is not are multiples: Type of cache, algorithm ... . * Qualitatively all caches will tend to load chunks of data that you read multiple-time, or chunks * of data that probably you will read based on pattern analysis. A small example is a linear memory copy where * you read consecutively memory and you write on consecutive memory. * Modern CPU recognize such pattern and decide to load on cache the consecutive memory before * you actually require it. * * * Iterating the vector in the way described above has the advantage that when we do computation on particles * and its neighborhood with the sequence described above it will happen that: * * * If to process a particle A we read some neighborhood particles to process the next particle A+1 * we will probably read most of the previous particles. * * * In order to show in practice what happen we first show the graph when we do not reorder * * \htmlinclude Vector/4_reorder/no_reorder.html * * The measure has oscillation but we see an asymptotic behavior from 0.04 in the initial condition to * 0.124 . Below we show what happen when we use iterator from the Cell list hilbert * * \htmlinclude Vector/4_reorder/comp_reord.html * * In cases where particles does not move or move very slowly consider to use data-reordering, because it can * give **8-10% speedup** * * \see \ref e4_reo * * ## Timers ## * * In order to collect the time of the force calculation we insert two timers around the function * calc_force. The overall performance is instead calculated with another timer around the time stepping * * \snippet Vector/4_reorder/main_data_ord.cpp timer start * \snippet Vector/4_reorder/main_data_ord.cpp timer stop * * \see \ref e3_md_vi * * */ //! \cond [md steps] \endcond // Get the Cell list structure auto NN = vd.getCellList_hilb(r_cut); // calculate forces calc_forces(vd,NN,sigma12,sigma6); unsigned long int f = 0; timer time2; time2.start(); #ifndef TEST_RUN size_t Nstep = 30000; #else size_t Nstep = 300; #endif // MD time stepping for (size_t i = 0; i < Nstep ; i++) { // Get the iterator auto it3 = vd.getDomainIterator(); // integrate velicity and space based on the calculated forces (Step1) while (it3.isNext()) { auto p = it3.get(); // here we calculate v(tn + 0.5) vd.template getProp<velocity>(p)[0] += 0.5*dt*vd.template getProp<force>(p)[0]; vd.template getProp<velocity>(p)[1] += 0.5*dt*vd.template getProp<force>(p)[1]; vd.template getProp<velocity>(p)[2] += 0.5*dt*vd.template getProp<force>(p)[2]; // here we calculate x(tn + 1) vd.getPos(p)[0] += vd.template getProp<velocity>(p)[0]*dt; vd.getPos(p)[1] += vd.template getProp<velocity>(p)[1]*dt; vd.getPos(p)[2] += vd.template getProp<velocity>(p)[2]*dt; ++it3; } // Because we mooved the particles in space we have to map them and re-sync the ghost vd.map(); vd.template ghost_get<>(); timer time; if (i % 10 == 0) time.start(); // calculate forces or a(tn + 1) Step 2 calc_forces(vd,NN,sigma12,sigma6); if (i % 10 == 0) { time.stop(); x.add(i); y.add({time.getwct()}); } // Integrate the velocity Step 3 auto it4 = vd.getDomainIterator(); while (it4.isNext()) { auto p = it4.get(); // here we calculate v(tn + 1) vd.template getProp<velocity>(p)[0] += 0.5*dt*vd.template getProp<force>(p)[0]; vd.template getProp<velocity>(p)[1] += 0.5*dt*vd.template getProp<force>(p)[1]; vd.template getProp<velocity>(p)[2] += 0.5*dt*vd.template getProp<force>(p)[2]; ++it4; } // After every iteration collect some statistic about the confoguration if (i % 100 == 0) { // We write the particle position for visualization (Without ghost) vd.deleteGhost(); vd.write("particles_",f); // we resync the ghost vd.ghost_get<>(); // We calculate the energy double energy = calc_energy(vd,NN,sigma12,sigma6); auto & vcl = create_vcluster(); vcl.sum(energy); vcl.execute(); // We also print on terminal the value of the energy // only one processor (master) write on terminal if (vcl.getProcessUnitID() == 0) std::cout << std::endl << "Energy: " << energy << std::endl; f++; } } time2.stop(); std::cout << "Performance: " << time2.getwct() << std::endl; //! \cond [md steps] \endcond /*! * \page Vector_4_comp_reo Vector 4 computational reordering and cache friendliness * * ## Plotting graphs ## * * After we terminate the MD steps our vector x contains at which iteration we benchmark the force * calculation time, while y contains the measured time at that time-step. We can produce a graph X Y * * \note The graph produced is an svg graph that can be view with a browser. From the browser we can * also easily save the graph into pure svg format * * \snippet Vector/4_reorder/main_comp_ord.cpp google chart * */ //! \cond [google chart] \endcond // Google charts options, it store the options to draw the X Y graph GCoptions options; // Title of the graph options.title = std::string("Force calculation time"); // Y axis name options.yAxis = std::string("Time"); // X axis name options.xAxis = std::string("iteration"); // width of the line options.lineWidth = 1.0; // Object that draw the X Y graph GoogleChart cg; // Add the graph // The graph that it produce is in svg format that can be opened on browser cg.AddLinesGraph(x,y,options); // Write into html format cg.write("gc_plot2_out.html"); //! \cond [google chart] \endcond /*! * * \page Vector_4_comp_reo Vector 4 computational reordering and cache friendliness * * ## Finalize ## * * At the very end of the program we have always to de-initialize the library * * \snippet Vector/4_reorder/main_comp_ord.cpp finalize * */ //! \cond [finalize] \endcond openfpm_finalize(); //! \cond [finalize] \endcond /*! * * \page Vector_4_comp_reo Vector 4 computational reordering and cache friendliness * * # Full code # * * \include Vector/4_reorder/main_comp_ord.cpp * */ }