Permalink
Cannot retrieve contributors at this time
Join GitHub today
GitHub is home to over 28 million developers working together to host and review code, manage projects, and build software together.
Sign up
Fetching contributors…
| #![cfg_attr(feature = "cargo-clippy", allow(clippy::unreadable_literal))] | |
| //! This module provides the [`Keyword`](::card::keyword::Keyword) enum to | |
| //! classify lines according to what card type they belong to. The terms | |
| //! "Keyword" and "Card" are lingo from the FEM solver Pamcrash, but generally | |
| //! used among FEM solvers. | |
| //! | |
| //! Also provides the [`Keywords`](::card::keyword::Keywords) struct to hold the | |
| //! keywords of a [`Lines`](::lines::Lines) struct. Supposed to be kept in sync | |
| //! via [`Keywords::update`](::card::keyword::Keywords::update). | |
| use crate::lines::Lines; | |
| use std::ops::Deref; | |
| /// An enum to denote the several types of cards a line might belong to. | |
| #[derive(Copy, Clone, PartialEq, Debug)] | |
| pub enum Keyword { | |
| Comment, | |
| // Node | |
| Node, | |
| Cnode, | |
| Mass, | |
| Nsmas, | |
| Nsmas2, | |
| // Element | |
| Solid, | |
| Hexa20, | |
| Pent15, | |
| Penta6, | |
| Tetr10, | |
| Tetr4, | |
| Bshel, | |
| Tshel, | |
| Shell, | |
| Shel6, | |
| Shel8, | |
| Membr, | |
| Beam, | |
| Sprgbm, | |
| Bar, | |
| Spring, | |
| Joint, | |
| Kjoin, | |
| Mtojnt, | |
| Sphel, | |
| Sphelo, | |
| Gap, | |
| Impma, | |
| // Link | |
| Elink, | |
| Llink, | |
| Slink, | |
| Plink, | |
| Tied, | |
| // Part 3D | |
| PartSolid, | |
| PartBshel, | |
| PartTetra, | |
| PartSphel, | |
| PartCos3d, | |
| // Part 2D | |
| PartTshel, | |
| PartShell, | |
| PartMembr, | |
| // Part 1D | |
| PartBar, | |
| PartBeam, | |
| PartSpring, | |
| PartSprgbm, | |
| PartMbspr, | |
| PartJoint, | |
| PartKjoin, | |
| PartMbkjn, | |
| PartMtojnt, | |
| PartTied, | |
| PartSlink, | |
| PartElink, | |
| PartLlink, | |
| PartPlink, | |
| PartGap, | |
| // Constraint | |
| Mtoco, | |
| Otmco, | |
| Rbody0, | |
| Rbody1, | |
| Rbody2, | |
| Rbody3, | |
| // Auxiliaries | |
| Group, | |
| } | |
| impl Keyword { | |
| /// Return the length of the keyword in the pamcrash input file | |
| /// Should be 8 for all right now... | |
| #[inline] | |
| pub fn len(self) -> u8 { | |
| 8 | |
| } | |
| #[inline] | |
| pub fn is_empty(self) -> bool { | |
| false | |
| } | |
| /// Parse a string to determine if it starts with the keyword of a card. | |
| #[inline] | |
| pub fn parse(s: &[u8]) -> Option<Keyword> { | |
| use self::Keyword::*; | |
| use byteorder::{BigEndian, ReadBytesExt}; | |
| let len = s.len(); | |
| if len == 0 { | |
| None | |
| } else if s[0] == b'#' || s[0] == b'$' { | |
| Some(Comment) | |
| } else if len < 8 { | |
| None | |
| } else { | |
| let mut start = &s[0..8]; | |
| let num = match start.read_u64::<BigEndian>() { | |
| Ok(n) => n, | |
| Err(_) => return None, | |
| }; | |
| match num { | |
| // Node | |
| // NODE | |
| 5642803921800933152 => Some(Node), | |
| // b"CNODE / " | |
| 4849901003360710432 => Some(Cnode), | |
| // b"MASS / " | |
| 5566822230893014816 => Some(Mass), | |
| // b"NSMAS / " | |
| 5643939700988194592 => Some(Nsmas), | |
| // b"NSMAS2/ " | |
| 5643939700989374240 => Some(Nsmas2), | |
| // b"SOLID / " | |
| 6003100705867444000 => Some(Solid), | |
| // b"HEXA20/ " | |
| 5207665581161983776 => Some(Hexa20), | |
| // b"PENT15/ " | |
| 5784115419937058592 => Some(Pent15), | |
| // b"PENTA6/ " | |
| 5784115420205559584 => Some(Penta6), | |
| // b"TETR10/ " | |
| 6072352384568274720 => Some(Tetr10), | |
| // b"TETR4 / " | |
| 6072352384617557792 => Some(Tetr4), | |
| // b"BSHEL / " | |
| 4779243092037349152 => Some(Bshel), | |
| // b"TSHEL / " | |
| 6076279784720052000 => Some(Tshel), | |
| // b"SHELL / " | |
| 6001122697468194592 => Some(Shell), | |
| // b"SHEL6 / " | |
| 6001122697099095840 => Some(Shel6), | |
| // b"SHEL8 / " | |
| 6001122697132650272 => Some(Shel8), | |
| // b"MEMBR / " | |
| 5567941461554507552 => Some(Membr), | |
| // b"BEAM / " | |
| 4775294779403546400 => Some(Beam), | |
| // b"SPRGBM/ " | |
| 6003388769293381408 => Some(Sprgbm), | |
| // b"BAR / " | |
| 4774187377920847648 => Some(Bar), | |
| // b"SPRING/ " | |
| 6003388778084249376 => Some(Spring), | |
| // b"JOINT / " | |
| 5354579082734481184 => Some(Joint), | |
| // b"KJOIN / " | |
| 5425235877383122720 => Some(Kjoin), | |
| // b"MTOJNT/ " | |
| 5572165819524460320 => Some(Mtojnt), | |
| // b"SPHEL / " | |
| 6003377765751992096 => Some(Sphel), | |
| // b"SPHELO/ " | |
| 6003377765755072288 => Some(Sphelo), | |
| // b"GAP / " | |
| 5134473149087231776 => Some(Gap), | |
| // b"IMPMA / " | |
| 5281966230710791968 => Some(Impma), | |
| // b"ELINK / " | |
| 4993446687463714592 => Some(Elink), | |
| // b"LLINK / " | |
| 5497849845729210144 => Some(Llink), | |
| // b"SLINK / " | |
| 6002253003994705696 => Some(Slink), | |
| // b"PLINK / " | |
| 5786080221880921888 => Some(Plink), | |
| // b"TIED / " | |
| 6073461731384897312 => Some(Tied), | |
| // b"PART / " | |
| 5782993917790138144 => { | |
| if len < 24 { | |
| None | |
| } else { | |
| let mut p = &s[16..24]; | |
| let num2 = match p.read_u64::<BigEndian>() { | |
| Ok(n) => n, | |
| Err(_) => return None, | |
| }; | |
| match num2 { | |
| // " SOLID", " SOLID ", " SOLID ", "SOLID " | |
| 2314885750653208900 | 2314941808515826720 | |
| | 2329292621345988640 | 6003100705867440160 => Some(PartSolid), | |
| // "BSHEL ", " BSHEL ", " BSHEL ", " BSHEL" | |
| 4779243092037345312 | 2324511927541964832 | |
| | 2314923133930654752 | 2314885677705610572 => Some(PartBshel), | |
| // "TETRA ", " TETRA ", " TETRA ", " TETRA" | |
| 6072352384835657760 | 2329563135716958240 | |
| | 2314942865212588320 | 2314885754780930625 => Some(PartTetra), | |
| // "SPHEL ", " SPHEL ", " SPHEL ", " SPHEL" | |
| 6003377765751988256 | 2329293703611162656 | |
| | 2314941812743425056 | 2314885750669722956 => Some(PartSphel), | |
| // "COS3D ", " COS3D ", " COS3D ", " COS3D" | |
| 4850186803352707104 | 2324789051414290464 | |
| | 2314924216445781024 | 2314885681934185284 => Some(PartCos3d), | |
| // "TSHEL ", " TSHEL ", " TSHEL ", " TSHEL" | |
| 6076279784720048160 | 2329578477122756640 | |
| | 2314942925139954720 | 2314885755015021900 => Some(PartTshel), | |
| // "SHELL ", " SHELL ", " SHELL ", " SHELL" | |
| 6001122697468190752 | 2329284894750679072 | |
| | 2314941778333813792 | 2314885750535310412 => Some(PartShell), | |
| // "MEMBR ", " MEMBR ", " MEMBR ", " MEMBR" | |
| 5567941461554503712 | 2327592780547891232 | |
| | 2314935168512709152 | 2314885724715696722 => Some(PartMembr), | |
| // "BAR ", " BAR ", " BAR ", " BAR ", " BAR ", | |
| // " BAR" | |
| 4774187377920843808 | 2324492178658697248 | |
| | 2314923056786579488 | 2314885677404266528 | |
| | 2314885531391054368 | 2314885530820690258 => Some(PartBar), | |
| // "BEAM ", " BEAM ", " BEAM ", " BEAM ", " BEAM" | |
| 4775294779403542560 | 2324496504445739040 | |
| | 2314923073684185120 | 2314885677470272800 | |
| | 2314885531391312205 => Some(PartBeam), | |
| // "SPRING ", " SPRING ", " SPRING" | |
| 6003388778084245536 | 2329293746628085536 | |
| | 2314941812911459911 => Some(PartSpring), | |
| // "SPRGBM ", " SPRGBM ", " SPRGBM" | |
| 6003388769293377568 | 2329293746593746208 | |
| | 2314941812911325773 => Some(PartSprgbm), | |
| // "MBSPR ", " MBSPR ", " MBSPR ", " MBSPR" | |
| 5567103693823680544 | 2327589508017692704 | |
| | 2314935155729388064 | 2314885724665761874 => Some(PartMbspr), | |
| // "JOINT ", " JOINT ", " JOINT ", " JOINT" | |
| 5354579082734477344 | 2326759333755625504 | |
| | 2314931912861176864 | 2314885711998307924 => Some(PartJoint), | |
| // "KJOIN ", " KJOIN ", " KJOIN ", " KJOIN" | |
| 5425235877383118880 | 2327035336859721760 | |
| | 2314932990998302240 | 2314885716209781070 => Some(PartKjoin), | |
| // "MTOJNT ", " MTOJNT ", " MTOJNT" | |
| 5572165819524456480 | 2327609281946211360 | |
| | 2314935232971296340 => Some(PartMtojnt), | |
| // "MBKJN ", " MBKJN ", " MBKJN ", " MBKJN" | |
| 5567094871893745696 | 2327589473557028896 | |
| | 2314935155594776096 | 2314885724665236046 => Some(PartMbkjn), | |
| // "TIED ", " TIED ", " TIED ", " TIED ", " TIED" | |
| 6073461731384893472 | 2329567469101916192 | |
| | 2314942882139873312 | 2314885754847052832 | |
| | 2314885531693565252 => Some(PartTied), | |
| // "SLINK ", " SLINK ", " SLINK ", " SLINK" | |
| 6002253003994701856 | 2329289310010548256 | |
| | 2314941795580922656 | 2314885750602681931 => Some(PartSlink), | |
| // "ELINK ", " ELINK ", " ELINK ", " ELINK" | |
| 4993446687463710752 | 2325348660336599072 | |
| | 2314926402418133792 | 2314885690473139787 => Some(PartElink), | |
| // "LLINK ", " LLINK ", " LLINK ", " LLINK" | |
| 5497849845729206304 | 2327318985173573664 | |
| | 2314934098999528224 | 2314885720537910859 => Some(PartLlink), | |
| // "PLINK ", " PLINK ", " PLINK ", " PLINK" | |
| 5786080221880918048 | 2328444885080416288 | |
| | 2314938497046039328 | 2314885737717780043 => Some(PartPlink), | |
| // "GAP ", " GAP ", " GAP ", " GAP ", " GAP ", | |
| // " GAP" | |
| 5134473149087227936 | 2325899544952315936 | |
| | 2314928554311163936 | 2314885698878971936 | |
| | 2314885531474939936 | 2314885530821017936 => Some(PartGap), | |
| _ => None, | |
| } | |
| } | |
| } | |
| // Constraint | |
| // b"MTOCO / " | |
| 5572165789473058592 => Some(Mtoco), | |
| // b"OTMCO / " | |
| 5716278778525658912 => Some(Otmco), | |
| // b"RBODY / " | |
| 5927387214544645920 => { | |
| if len < 32 { | |
| None | |
| } else { | |
| let mut p = &s[24..32]; | |
| let num3 = match p.read_u64::<BigEndian>() { | |
| Ok(n) => n, | |
| Err(_) => return None, | |
| }; | |
| match num3 { | |
| // "0 ", " 0 ", " 0 ", " 0 ", " 0 ", | |
| // " 0 ", " 0 ", " 0" | |
| 3467807035425300512 | 2319389130445824032 | |
| | 2314903123004497952 | 2314885599537930272 | |
| | 2314885531086888992 | 2314885530819502112 | |
| | 2314885530818457632 | 2314885530818453552 => Some(Rbody0), | |
| // "1 ", " 1 ", " 1 ", " 1 ", " 1 ", | |
| // " 1 ", " 1 ", " 1" | |
| 3539864629463228448 | 2319670605422534688 | |
| | 2314904222516125728 | 2314885603832897568 | |
| | 2314885531103666208 | 2314885530819567648 | |
| | 2314885530818457888 | 2314885530818453553 => Some(Rbody1), | |
| // "2 ", " 2 ", " 2 ", " 2 ", " 2 ", | |
| // " 2 ", " 2 ", " 2" | |
| 3611922223501156384 | 2319952080399245344 | |
| | 2314905322027753504 | 2314885608127864864 | |
| | 2314885531120443424 | 2314885530819633184 | |
| | 2314885530818458144 | 2314885530818453554 => Some(Rbody2), | |
| // "3 ", " 3 ", " 3 ", " 3 ", " 3 ", | |
| // " 3 ", " 3 ", " 3" | |
| 3683979817539084320 | 2320233555375956000 | |
| | 2314906421539381280 | 2314885612422832160 | |
| | 2314885531137220640 | 2314885530819698720 | |
| | 2314885530818458400 | 2314885530818453555 => Some(Rbody3), | |
| _ => None, | |
| } | |
| } | |
| } | |
| // Auxiliaries | |
| // b"GROUP / " | |
| 5139257352618258208 => Some(Group), | |
| _ => None, | |
| } | |
| } | |
| } | |
| } | |
| #[derive(Debug, Default)] | |
| pub struct Keywords(Vec<Option<Keyword>>); | |
| impl Keywords { | |
| /// Create a [`Keywords`](::card::keyword::Keywords) struct by parsing a | |
| /// [`Lines`](::lines::Lines) struct. | |
| pub fn from_lines(lines: &Lines) -> Keywords { | |
| let v: Vec<Option<Keyword>> = lines.iter().map(Keyword::parse).collect(); | |
| Keywords(v) | |
| } | |
| /// Update a [`Keywords`](::card::keyword::Keywords) struct by parsing a | |
| /// `Vec<String>` and splicing in the result on the interval `first..last`. | |
| pub fn update(&mut self, first: usize, last: usize, linedata: &[String]) { | |
| let range = first..last; | |
| let _ = self | |
| .0 | |
| .splice(range, linedata.iter().map(|l| Keyword::parse(l.as_ref()))); | |
| } | |
| // TODO: Efficient? Correct? | |
| pub fn first_before(&self, line: u64) -> u64 { | |
| self | |
| .get(..=line as usize) | |
| .unwrap_or(&[]) | |
| .iter() | |
| .enumerate() | |
| .rfind(|(_i, k)| k.is_some() && **k != Some(Keyword::Comment)) | |
| .unwrap_or((0, &None)) | |
| .0 as u64 | |
| } | |
| // TODO: Efficient? Correct? | |
| pub fn first_after(&self, line: u64) -> u64 { | |
| self | |
| .iter() | |
| .enumerate() | |
| .skip(line as usize) | |
| .find(|(_i, k)| k.is_some() && **k != Some(Keyword::Comment)) | |
| .unwrap_or((self.len(), &None)) | |
| .0 as u64 | |
| } | |
| } | |
| impl Deref for Keywords { | |
| type Target = [Option<Keyword>]; | |
| fn deref(&self) -> &[Option<Keyword>] { | |
| &self.0 | |
| } | |
| } | |
| #[cfg(test)] | |
| mod tests { | |
| use crate::card::keyword::{Keyword::*, Keywords}; | |
| #[test] | |
| fn first() { | |
| let kw = Keywords(vec![ | |
| None, | |
| None, | |
| Some(Node), | |
| None, | |
| None, | |
| Some(Comment), | |
| Some(Node), | |
| Some(Comment), | |
| None, | |
| ]); | |
| assert_eq!(2, kw.first_before(2)); | |
| assert_eq!(2, kw.first_after(2)); | |
| assert_eq!(2, kw.first_before(4)); | |
| assert_eq!(6, kw.first_after(4)); | |
| assert_eq!(0, kw.first_before(1)); | |
| assert_eq!(9, kw.first_after(7)); | |
| } | |
| #[test] | |
| fn first_oneline() { | |
| let mut kw = Keywords(vec![Some(Node)]); | |
| assert_eq!(0, kw.first_before(0)); | |
| assert_eq!(0, kw.first_after(0)); | |
| kw = Keywords(vec![Some(Comment)]); | |
| assert_eq!(0, kw.first_before(0)); | |
| assert_eq!(1, kw.first_after(0)); | |
| assert_eq!(0, kw.first_before(1)); | |
| assert_eq!(1, kw.first_after(1)); | |
| } | |
| } |